Python的GIL全局解釋鎖只存在CPython解釋器焚廊,使用其他語(yǔ)言編寫(xiě)的解釋器是沒(méi)有這個(gè)問(wèn)題的
GIL面試題如下
描述Python GIL的概念,以及它對(duì)python多線程的影響习劫?
編寫(xiě)一個(gè)多線程抓取網(wǎng)頁(yè)的程序咆瘟,并闡明多線程抓取程序是否可比單線程性能有提升,并解釋原因诽里。
參考答案:
1. Python語(yǔ)言和GIL沒(méi)有半毛錢(qián)關(guān)系袒餐。僅僅是由于歷史原因在Cpython虛擬機(jī)(解釋器),難以移除GIL。
2. GIL:全局解釋器鎖灸眼。每個(gè)線程在執(zhí)行的過(guò)程都需要先獲取GIL卧檐,保證同一時(shí)刻只有一個(gè)線程可以執(zhí)行代碼
3. 線程釋放GIL鎖的情況: 在IO操作等可能會(huì)引起阻塞的system call之前,可以暫時(shí)釋放GIL幢炸,
但在執(zhí)行完畢后泄隔,必須重新獲取GIL Python 3.x使用計(jì)時(shí)器(執(zhí)行時(shí)間達(dá)到閾值后,當(dāng)前線程釋放GIL)
或Python 2.x宛徊,tickets計(jì)數(shù)達(dá)到100
Python使用多進(jìn)程是可以利用多核的CPU資源的佛嬉。
3. 多線程爬取比單線程性能有提升,因?yàn)橛龅絀O阻塞會(huì)自動(dòng)釋放GIL鎖
深拷貝闸天、淺拷貝
1. 淺拷貝
淺拷貝是對(duì)于一個(gè)對(duì)象的頂層拷貝
通俗的理解是:拷貝了引用暖呕,并沒(méi)有拷貝內(nèi)容
2. 深拷貝
深拷貝是對(duì)于一個(gè)對(duì)象所有層次的拷貝(遞歸)
淺拷貝對(duì)不可變類(lèi)型和可變類(lèi)型的copy不同
import copy
copy.copy() 和 copy.deepcopy() 的兩個(gè)copy方法
對(duì)于可變類(lèi)型,會(huì)進(jìn)行淺拷貝
對(duì)于不可變類(lèi)型苞氮,不會(huì)拷貝湾揽,僅僅是指向
對(duì)于不可變類(lèi)型包含可變類(lèi)型,copy.copy() 淺拷貝笼吟,copy.deepcopy() 全部拷貝
如果copy.copy拷貝的是元組库物,那么它不會(huì)進(jìn)行拷貝,僅僅是指向
原因:因?yàn)樵M是不可變類(lèi)型贷帮,那么意味著數(shù)據(jù)一定不能修改戚揭,因此copy.copy的時(shí)候它會(huì)自動(dòng)判斷,
如果是元組就是指向
如果拷貝的是元組包含列表類(lèi)型的數(shù)據(jù)撵枢,copy.copy() 進(jìn)行淺拷貝民晒,copy.deepcopy() 進(jìn)行全部拷貝
測(cè)試 深拷貝 和 淺拷貝
1. test
import copy
a = [11, 22]
b = [33, 44]
c = [a, b]
d = copy.copy(c)
print(id(c) == id(d)) # False
print(id(c[0]) == id(d[0])) # True
copy.copy() 拷貝可變類(lèi)型,只是淺拷貝
2. test
import copy
a = (11, 22)
b = (33, 44)
c = (a, b)
d = copy.copy(c)
print(id(c) == id(d)) # True
print(id(c[0]) == id(d[0])) # True
copy.copy() 拷貝不可變類(lèi)型锄禽,只是指向
3. test
import copy
a = [11, 22]
b = [33, 44]
c = [a, b]
d = copy.deepcopy(c)
print(id(c) == id(d)) # False
print(id(c[0]) == id(d[0])) # False
copy.deepcopy() 拷貝可變類(lèi)型潜必,全部拷貝
4. test
import copy
a = (11, 22)
b = (33, 44)
c = (a, b)
d = copy.deepcopy(c)
print(id(c) == id(d)) # True
print(id(c[0]) == id(d[0])) # True
copy.deepcopy() 拷貝不可變類(lèi)型,還是指向
5. test 不可變類(lèi)型包含可變類(lèi)型沃但,就全部拷貝
import copy
a = [11, 22]
b = [33, 44]
c = (a, b)
d = copy.deepcopy(c)
print(id(c) == id(d)) # False
print(id(c[0]) == id(d[0])) # False
copy.deepcopy() 不可變類(lèi)型包含可變類(lèi)型磁滚,就全部拷貝
c = [11, 22]
d = c[:] 與 d = copy.copy(c) 一樣,屬于淺拷貝
對(duì)于字典來(lái)說(shuō)宵晚,有一點(diǎn)不同:
import copy
a = dict(name="libai", maybe=[11, 22])
b = copy.copy(a)
print(id(a) == id(b)) # False 這里的字典是不相等的
print(id(a["maybe"]) == id(b["maybe"])) # True 鍵值相等
copy.copy() 拷貝內(nèi)部包含可變類(lèi)型
import copy
a = dict(name="libai", maybe=[11, 22])
b = copy.deepcopy(a)
print(id(a) == id(b)) # False 這里的也是不相等
print(id(a["maybe"]) == id(b["maybe"])) # False 都拷貝了
copy.deepcopy() 對(duì)于字典恨旱,全部拷貝
一般來(lái)說(shuō),函數(shù)傳遞的都是值的引用坝疼,必要時(shí)候需要用到深拷貝
Python 的私有化
1. xx:公有變量
2. _x:?jiǎn)吻爸孟聞澗€,私有化屬性或方法,from somemodule import * 禁止導(dǎo)入谆沃,類(lèi)對(duì)象和子類(lèi)可以訪問(wèn)
3. __xx:雙前置下劃線,避免與子類(lèi)中的屬性命名沖突钝凶,無(wú)法在外部直接訪問(wèn)(名字重整所以訪問(wèn)不到)
4. __xx__:雙前后下劃線,用戶(hù)名字空間的魔法對(duì)象或?qū)傩浴@?__init__ , 不要自己發(fā)明這樣的名字
5. xx_:?jiǎn)魏笾孟聞澗€耕陷,用于避免與Python關(guān)鍵詞的沖突
總結(jié):
1. 父類(lèi)中屬性名為_(kāi)_名字的掂名,子類(lèi)不繼承,子類(lèi)不能訪問(wèn)
2. 如果在子類(lèi)中向__名字賦值哟沫,那么會(huì)在子類(lèi)中定義的一個(gè)與父類(lèi)相同名字的屬性
3. _名的變量饺蔑、函數(shù)、類(lèi)在使用from xxx import *時(shí)都不會(huì)被導(dǎo)入
導(dǎo)入模塊
1. 直接 import
2. 通過(guò)sys模塊導(dǎo)入自定義模塊的path
先導(dǎo)入sys模塊
然后通過(guò)sys.path.append(path) 函數(shù)來(lái)導(dǎo)入自定義模塊所在的目錄
導(dǎo)入自定義模塊嗜诀。
import sys
sys.path.append(r"C:\Users\Pwcong\Desktop\python")
import pwcong
pwcong.hi()
3. 通過(guò)pth文件找到自定義模塊
動(dòng)態(tài)導(dǎo)入
#a 下的 test.py 文件
def test_a():
print('this is a')
def _test_b():
print('this is b')
(1)導(dǎo)入模塊 from xxx import *
from a.test import *
test_a()
test_b()
輸出結(jié)果:
#找不到 test_b 函數(shù)猾警,就算改成_test_b 也是一樣
NameError: name 'test_b' is not defined
Process finished with exit code 1
(2)導(dǎo)入模塊 __import__('a.test')
module_t = __import__('a.test') #傳入字符串
print(module_t) #定位到 test 文件的頂級(jí)目錄 a
module_t.test.test_a()
module_t.test._test_b() #私有函數(shù)也可調(diào)用
輸出結(jié)果:
<module 'a' (namespace)> # a 目錄
this is a
this is b
(3)導(dǎo)入模塊 importlib
import importlib
module_t = importlib.import_module('a.test')
print(module_t) #直接定位到 test
module_t.test_a()
module_t._test_b()
輸出結(jié)果:
<module 'a.test' from 'C:\\Users\\libai\\PycharmProjects\\begin\\a\\test.py'> #a.test
this is a
this is b
導(dǎo)入模塊時(shí)的路徑搜索
在 ipython 中輸入下面的命令
import sys
sys.path
打印結(jié)果:
['',
'D:\\anaconda\\Scripts',
'D:\\anaconda\\python36.zip',
'D:\\anaconda\\DLLs',
'D:\\anaconda\\lib',
'D:\\anaconda',
'D:\\anaconda\\lib\\site-packages',
'D:\\anaconda\\lib\\site-packages\\win32',
'D:\\anaconda\\lib\\site-packages\\win32\\lib',
'D:\\anaconda\\lib\\site-packages\\Pythonwin',
'D:\\anaconda\\lib\\site-packages\\IPython\\extensions',
'C:\\Users\\libai\\.ipython']
導(dǎo)入模塊時(shí)的路徑搜索
1. 從上面列出的目錄里依次查找要導(dǎo)入的模塊文件
2. '' 表示當(dāng)前路徑
3. 列表中的路徑的先后順序代表了python解釋器在搜索模塊時(shí)的先后順序
程序執(zhí)行時(shí)添加新的模塊路徑
sys.path.append('/home/itcast/xxx')
sys.path.insert(0, '/home/itcast/xxx') # 插入到第一個(gè)位置,可以確保先搜索這個(gè)路徑
重新導(dǎo)入模塊
模塊被導(dǎo)入后隆敢,import module不能重新導(dǎo)入模塊发皿,重新導(dǎo)入需用reload
注意:from xxxx import 變量 時(shí),要注意導(dǎo)入的是變量的值拂蝎,而不是一個(gè)指向
封裝穴墅、繼承、多態(tài) 是面向?qū)ο蟮?大特性
多繼承
super().__init__相對(duì)于類(lèi)名.__init__温自,在單繼承上用法基本無(wú)差
但在多繼承上有區(qū)別玄货,super方法能保證每個(gè)父類(lèi)的方法只會(huì)執(zhí)行一次,而使用類(lèi)名的方法會(huì)導(dǎo)致方法被執(zhí)行多次
多繼承時(shí)悼泌,使用super方法松捉,對(duì)父類(lèi)的傳參數(shù),應(yīng)該是由于python中super的算法導(dǎo)致的原因券躁,
必須把參數(shù)全部傳遞惩坑,否則會(huì)報(bào)錯(cuò)
單繼承時(shí),使用super方法也拜,則不能全部傳遞以舒,只能傳父類(lèi)方法所需的參數(shù),否則會(huì)報(bào)錯(cuò)
多繼承時(shí)慢哈,相對(duì)于使用類(lèi)名.__init__方法蔓钟,要把每個(gè)父類(lèi)全部寫(xiě)一遍, 而使用super方法,
只需寫(xiě)一句話(huà)便執(zhí)行了全部父類(lèi)的方法卵贱,這也是為何多繼承需要全部傳參的一個(gè)原因
使用 print(Grandson.__mro__) 顯示類(lèi)的繼承順序(前提:Son1滥沫、Son2都是Parent的子類(lèi))
(<class '__main__.Grandson'>, <class '__main__.Son1'>, <class '__main__.Son2'>, <class '__main__.Parent'>, <class 'object'>)
面試題:以下的代碼的輸出將是什么? 說(shuō)出你的答案并解釋。
class Parent(object):
x = 1
class Child1(Parent):
pass
class Child2(Parent):
pass
print(Parent.x, Child1.x, Child2.x)
Child1.x = 2
print(Parent.x, Child1.x, Child2.x)
Parent.x = 3
print(Parent.x, Child1.x, Child2.x)
答案, 以上代碼的輸出是:
1 1 1
1 2 1
3 2 3
說(shuō)明:
使你困惑或是驚奇的是關(guān)于最后一行的輸出是 3 2 3 而不是 3 2 1键俱。為什么改變了 Parent.x 的值還會(huì)
改變 Child2.x 的值兰绣,但是同時(shí) Child1.x 值卻沒(méi)有改變?
這個(gè)答案的關(guān)鍵是编振,在 Python 中缀辩,類(lèi)變量在內(nèi)部是作為字典處理的。如果一個(gè)變量的名字沒(méi)有在當(dāng)前類(lèi)
的字典中發(fā)現(xiàn),將搜索祖先類(lèi)(比如父類(lèi))直到被引用的變量名被找到(如果這個(gè)被引用的變量名既沒(méi)有
在自己所在的類(lèi)又沒(méi)有在祖先類(lèi)中找到臀玄,會(huì)引發(fā)一個(gè) AttributeError 異常 )瓢阴。
因此,在父類(lèi)中設(shè)置 x = 1 會(huì)使得類(lèi)變量 x 在引用該類(lèi)和其任何子類(lèi)中的值為 1健无。
這就是因?yàn)榈谝粋€(gè) print 語(yǔ)句的輸出是 1 1 1荣恐。
隨后,如果任何它的子類(lèi)重寫(xiě)了該值(例如累贤,我們執(zhí)行語(yǔ)句 Child1.x = 2)叠穆,然后,
該值僅僅在子類(lèi)中被改變畦浓。這就是為什么第二個(gè) print 語(yǔ)句的輸出是 1 2 1痹束。
最后,如果該值在父類(lèi)中被改變(例如讶请,我們執(zhí)行語(yǔ)句 Parent.x = 3)祷嘶,這個(gè)改變會(huì)影響到任何未重寫(xiě)
該值的子類(lèi)當(dāng)中的值(在這個(gè)示例中被影響的子類(lèi)是 Child2)。
這就是為什么第三個(gè) print 輸出是 3 2 3夺溢。
用新式類(lèi)作輸入類(lèi)型檢測(cè)论巍,get,set,del
class Type:
def __init__(self, key):
self.key = key
def __get__(self, instance, owner):
print('get 方法')
print(instance)
print(owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set 方法')
print(instance)
print(value)
if not isinstance(value,str):
print("必須傳入字符串")
return
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('del 方法')
print(instance)
del instance.__dict__[self.key]
class earth:
name = Type('name')
def __init__(self, name, age):
self.name = name
self.age = age
e = earth('libai', 20)
print(e.__dict__)
print(e.name)
e.name = 12
print(e.__dict__)
print('----------------------------------')
del e.name
print(e.__dict__)
輸出結(jié)果:
set 方法
<__main__.earth object at 0x000002257741AEF0>
libai
{'name': 'libai', 'age': 20}
get 方法
<__main__.earth object at 0x000002257741AEF0>
<class '__main__.earth'>
libai
set 方法
<__main__.earth object at 0x000002257741AEF0>
12
必須傳入字符串
{'name': 12, 'age': 20}
----------------------------------
del 方法
<__main__.earth object at 0x000002257741AEF0>
{'age': 20}
改進(jìn)上面的程序,使得可以檢測(cè) 多種類(lèi)型
class Type:
def __init__(self, key, except_type):
self.key = key
self.except_type = except_type
def __get__(self, instance, owner):
print('get 方法')
print(instance)
print(owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set 方法')
print(instance)
print(value)
if not isinstance(value,self.except_type):
print("必須傳入 %s " %self.except_type)
return
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('del 方法')
print(instance)
del instance.__dict__[self.key]
class earth:
name = Type('name', str)
age = Type('age', int)
def __init__(self, name, age):
self.name = name
self.age = age
e = earth('libai', 20)
print('---------------------------------')
e.name = 20
print('---------------------------------')
e.age = 'bbs'
輸出結(jié)果:
set 方法
<__main__.earth object at 0x000002254086D080>
libai
set 方法
<__main__.earth object at 0x000002254086D080>
20
---------------------------------
set 方法
<__main__.earth object at 0x000002254086D080>
20
必須傳入 <class 'str'>
---------------------------------
set 方法
<__main__.earth object at 0x000002254086D080>
bbs
必須傳入 <class 'int'>
Python 的閉包
def deco(x, y):
def wrapper(z):
return x+y+z
return wrapper
d = deco(100, 200)
print(d(300)) // 600
思考:函數(shù)风响、匿名函數(shù)嘉汰、閉包、對(duì)象 當(dāng)做實(shí)參時(shí) 有什么區(qū)別状勤?
1. 匿名函數(shù)能夠完成基本的簡(jiǎn)單功能鞋怀,,持搜,傳遞是這個(gè)函數(shù)的引用 只有功能
2. 普通函數(shù)能夠完成較為復(fù)雜的功能密似,,葫盼,傳遞是這個(gè)函數(shù)的引用 只有功能
3. 閉包能夠?qū)⑤^為復(fù)雜的功能残腌,,贫导,傳遞是這個(gè)閉包中的函數(shù)以及數(shù)據(jù)抛猫,因此傳遞是功能+數(shù)據(jù)
4. 對(duì)象能夠完成最為復(fù)雜的功能,孩灯,闺金,傳遞是很多數(shù)據(jù)+很多功能,因此傳遞是功能+數(shù)據(jù)
裝飾器峰档,改成類(lèi)型檢測(cè)掖看,如果檢測(cè)到不匹配匣距,就print 和不寫(xiě)入
def deco(**kwargs): #接收參數(shù)傳入**kwargs
def wrapper(obj): #返回的 wrapper 傳入earth
print('========================')
for key,value in kwargs.items(): # .items() 格式為元組
setattr(obj, key, Type(key, value))
return obj
print(kwargs)
return wrapper
#類(lèi)型傳入檢測(cè)
class Type:
def __init__(self, key, except_type):
self.key = key
self.except_type = except_type
def __get__(self, instance, owner):
print('get 方法')
print(instance)
print(owner)
return instance.__dict__[self.key]
def __set__(self, instance, value):
print('set 方法')
print(instance)
print(value)
if not isinstance(value,self.except_type):
print("必須傳入 %s " %self.except_type)
return
instance.__dict__[self.key] = value
def __delete__(self, instance):
print('del 方法')
print(instance)
del instance.__dict__[self.key]
@deco(name=str,age=int) #name 傳入類(lèi)型 str,age傳入類(lèi)型 int
class earth:
def __init__(self, name, age):
self.name = name
self.age = age
e = earth('libai', '23') #觸發(fā)set方法
print('*************************************************')
print(earth.__dict__)
print(e.__dict__)
輸出結(jié)果:
{'name': <class 'str'>, 'age': <class 'int'>}
========================
set 方法
<__main__.earth object at 0x0000025C38B4E080>
libai
set 方法
<__main__.earth object at 0x0000025C38B4E080>
23
必須傳入 <class 'int'>
*************************************************
{'__module__': '__main__', '__init__': <function earth.__init__ at 0x0000025C38B34950>, '__dict__': <attribute '__dict__' of 'earth' objects>, '__weakref__': <attribute '__weakref__' of 'earth' objects>, '__doc__': None, 'name': <__main__.Type object at 0x0000025C38B4AF98>, 'age': <__main__.Type object at 0x0000025C38B4E048>}
{'name': 'libai'}
@property 就是把裝飾的類(lèi)或者函數(shù)當(dāng)成參數(shù)傳入 property(類(lèi)) 中哎壳,執(zhí)行完后把返回值再賦給所裝飾的類(lèi),下面是自定義的 @property尚卫,與原生的@property 有類(lèi)似的功能
class Lazyproperty:
def __init__(self, func):
self.func = func
print('func = ', self.func)
def __get__(self, instance, owner):
print('instance = ', instance)
print('owner = ', owner)
# 以下這句 self.func(instance) 被執(zhí)行并賦值給print打印時(shí)归榕,
# 會(huì)執(zhí)行一遍 test 函數(shù),這也就是為什么輸出結(jié)果中會(huì)有兩個(gè) test被打印
print('------------------>>>', self.func(instance))
print('***************************************************')
return self.func(instance)
class earth:
def __init__(self):
pass
@Lazyproperty
def test(self):
print('test')
return '你好嗎吱涉?'
e = earth()
print(e.test)
輸出結(jié)果:
func = <function earth.test at 0x0000021C699B47B8>
instance = <__main__.earth object at 0x0000021C699CAEB8>
owner = <class '__main__.earth'>
test
------------------>>> 你好嗎刹泄? # test 被打印兩次
***************************************************
test
你好嗎?
優(yōu)先級(jí)尋找十分重要啊怎爵,
class Lazyproperty:
def __init__(self, func):
self.func = func
def __get__(self, instance, owner):
print('get')
res = self.func(instance)
setattr(instance, self.func.__name__, res)
return res
# 如果存在 __set__ 方法特石,class Lazyproperty 為數(shù)據(jù)描述符,優(yōu)先級(jí)高于實(shí)例屬性鳖链,
# 尋找屬性時(shí)會(huì)優(yōu)先尋找 數(shù)據(jù)描述符姆蘸,就會(huì)每次執(zhí)行都調(diào)用一次 get 方法
# 現(xiàn)在不存在 __set__ 方法,class Lazyproperty 為非數(shù)據(jù)描述符芙委,優(yōu)先級(jí)低于實(shí)例屬性逞敷,
# 尋找屬性時(shí)會(huì)優(yōu)先尋找 實(shí)例屬性,
# 整個(gè)程序執(zhí)行過(guò)程:
# 首先呢灌侣,@Lazyproperty 會(huì)先執(zhí)行一遍推捐,把 test 函數(shù)當(dāng)成參數(shù)傳入,
# 實(shí)例化后再賦給test侧啼,下面牛柒,實(shí)例化 earth 類(lèi)為 e,直接傳參到
# self.x 和 self.y 痊乾;
# 調(diào)用 e.test 過(guò)程中皮壁,會(huì)先尋找 e 的實(shí)例屬性,實(shí)例屬性不存在 test符喝,
# 那就去找非數(shù)據(jù)描述符闪彼, class Lazyproperty 的 get 方法被執(zhí)行,
# instance 是類(lèi)的實(shí)例协饲,也就是 e 畏腕,self.func 就是 test,
# owner 是 earth 類(lèi)茉稠,在 earth 類(lèi)中的 test 函數(shù)必須傳入一個(gè)參數(shù)描馅,
# 也就是 instance ,self.func(instance) 執(zhí)行結(jié)果被存到 e.__dict__
# 實(shí)例屬性中而线,之后 get 方法就不會(huì)執(zhí)行了铭污,因?yàn)樵趯?shí)例屬性中找得到結(jié)果
# 可以實(shí)現(xiàn)不用每次執(zhí)行都計(jì)算一遍
# def __set__(self, instance, value):
# pass
class earth:
def __init__(self, x, y):
self.x = x
self.y = y
@Lazyproperty
def test(self):
return (self.x*self.y)
e = earth(10,22)
print(e.test)
print(e.test)
print(e.test)
print(e.__dict__)
輸出結(jié)果:
get
220
220
220
{'x': 10, 'y': 22, 'test': 220}
類(lèi)創(chuàng)建實(shí)例對(duì)象恋日,元類(lèi)創(chuàng)建類(lèi),python 中任何 class 定義的類(lèi)其實(shí)都是 type 類(lèi)實(shí)例化的對(duì)象嘹狞,類(lèi)也可以直接用 type 來(lái)創(chuàng)建
class Foo:
def __init__(self):
pass
def __init__(self):
pass
earth = type('earth',(object,),{'__init__':__init__,'x':28})
print(earth.__dict__)
print('---------------------------------------------------------')
print(Foo)
print(Foo.__dict__)
print(type(Foo))
print(type(type(type(Foo)))) # type 又是誰(shuí)創(chuàng)建的呢岂膳? 還是 type!
輸出結(jié)果:
{'__init__': <function __init__ at 0x0000019D88944598>, 'x': 28, '__module__': '__main__', '__dict__': <attribute '__dict__' of 'earth' objects>, '__weakref__': <attribute '__weakref__' of 'earth' objects>, '__doc__': None}
---------------------------------------------------------
<class '__main__.Foo'>
{'__module__': '__main__', '__init__': <function Foo.__init__ at 0x0000019D88944620>, '__dict__': <attribute '__dict__' of 'Foo' objects>, '__weakref__': <attribute '__weakref__' of 'Foo' objects>, '__doc__': None}
<class 'type'>
<class 'type'> # 類(lèi)的類(lèi)的類(lèi)的類(lèi)
自定義元類(lèi)
class MyType(type):
def __init__(self, a, b, c):
print('元類(lèi)的構(gòu)造函數(shù)執(zhí)行')
def __call__(self, *args, **kwargs):
obj = object .__new__(self)
self.__init__(obj, *args, **kwargs)
return obj
class Foo(metaclass=MyType):
def __init__(self, name):
self.name = name
f1 = Foo('alex')