【原創】Python 對象創建過程中元類, __new__, __call__, __init__ 的處理
原始type:
type是最原始的元類,其__call__方法是在你使用" t_class = type(classname_string, base_classes_tuple, attributes_dict)" 這種語法來使用時, 在__call__方法內使用又會調用type的__new__和__init__方法來創建classname_string的具體類,並初始化類信息。當type(***)調用完成, classname_string代表的類可以用來創建實例了。
元類調用過程: 原始type元類同理
如下流程:假設是MyMeta元類,而不是原始type元類
例子: MyClass = MyMeta(‘MyClass‘, bases, attributes)
my_meta_type = type(MyMeta)MyClass= my_meta_type.__call__(MyMeta, cls, bases, attributes)
在__call__中應該是如下操作:
MyClass = MyMeta.__new__(MyMeta, cls, bases, attributes) meta_class = MyClass.__metaclass__ meta_class.__init__(MyClass, cls, bases, attributes) return MyClass
最終返回MyClass類
上述元類有一個很令人迷惑的地方,需要註意到,當你的元類是自定義的元類的時候,
總結: 元類處理過程:定義一個類時,使用聲明或者默認的元類對該類進行創建,對元類求type運算,得到父元類(該類聲明的元類的父元類),調用父元類的__call__函數,在父元類的__call__函數中, 調用該類聲明的元類的__new__函數來創建對象(該函數需要返回一個對象(指類)實例),然後再調用該元類的__init__初始化該對象(此處對象是指類,因為是元類創建的對象)
你可以簡單實驗以下,自定義倆個元類,該倆個元類是父子關系,在定義一個類,設置使用自定義元類的子元類,發現會調用自定義元類的父元類中call的輸出,子元類的call並沒有輸出,在定義類的對象時才輸出了
例子如下:
class SuperMeta(type):
def __call__(metaname, clsname, baseclasses, attrs):
print ‘SuperMeta Called‘
clsob = type.__new__(metaname, clsname, baseclasses, attrs)
type.__init__(clsob, clsname, baseclasses, attrs)
return clsob
class MyMeta(type):
__metaclass__ = SuperMeta
def __call__(cls, *args, **kwargs):
print ‘MyMeta called‘, cls, args, kwargs
ob = object.__new__(cls, *args)
ob.__init__(*args)
return ob
print ‘create class‘
class Kls(object):
__metaclass__ = MyMeta
def __init__(self, data):
self.data = data
def printd(self):
print self.data
print ‘class created ---------------------‘
# 你會發現定義了 Kls 類後輸出了 SuperMeta 父元類的輸出
ik = Kls(‘arun‘)
ik.printd()
ik2 = Kls(‘avni‘)
ik2.printd()
# 定義Kls對象實例才真的執行了MyMeta的call
為什麽type會調用自己的呢,因為type的type還是type, 蛋疼一小會……
附加:
原始type的__call__應該是參數結構應該是:
metaname, clsname, baseclasses, attrs
原始type的__new__
metaname, clsname, baseclasses, attrs
原始type的__init__
class_obj, clsname, baseclasses, attrs
元類的__new__和__init__影響的是創建類對象的行為,父元類的__call__控制對子元類的 __new__,__init__的調用,就是說控制類對象的創建和初始化。父元類的__new__和__init__由更上層的控制,
一般來說,原始type是最初的父元類,其__new__和__init__是具有普遍意義的,即應該是分配內存、初始化相關信息等
元類__call__影響的是創建類的實例對象的行為,此時如果類自定義了__new__和__init__就可以控制類的對象實例的創建和初始化
參考:
http://pythoncentral.io/how-metaclasses-work-technically-in-python-2-and-3/
http://stackoverflow.com/questions/2608708/what-is-the-difference-between-type-and-type-new-in-python Florentin的答案
classKls(object): __metaclass__=MyMeta def__init__(self,data): self.data=data defprintd(self): printself.data
【原創】Python 對象創建過程中元類, __new__, __call__, __init__ 的處理