有微妙的差異,主要與遺傳有關。當使用 函數作爲元類時,生成的類實際上是type
, 的實例,並且可以不受限制地繼承;然而,元類功能 永遠不會被調用這樣的子類。當使用type
的子類作爲 元類時,生成的類將是該元類的一個實例,其子類也會是 ;但是,多重繼承將受到限制。
龍虎鬥的差異:
>>> def m1(name, bases, atts):
>>> print "m1 called for " + name
>>> return type(name, bases, atts)
>>>
>>> def m2(name, bases, atts):
>>> print "m2 called for " + name
>>> return type(name, bases, atts)
>>>
>>> class c1(object):
>>> __metaclass__ = m1
m1 called for c1
>>> type(c1)
<type 'type'>
>>> class sub1(c1):
>>> pass
>>> type(sub1)
<type 'type'>
>>> class c2(object):
>>> __metaclass__ = m2
m2 called for c2
>>> class sub2(c1, c2):
>>> pass
>>> type(sub2)
<type 'type'>
注意,定義SUB1和SUB2時,沒有元類函數被調用。 他們將創建完全一樣,如果c1和c2沒有元類,而是 已被創建後操作。
>>> class M1(type):
>>> def __new__(meta, name, bases, atts):
>>> print "M1 called for " + name
>>> return super(M1, meta).__new__(meta, name, bases, atts)
>>> class C1(object):
>>> __metaclass__ = M1
M1 called for C1
>>> type(C1)
<class '__main__.M1'>
>>> class Sub1(C1):
>>> pass
M1 called for Sub1
>>> type(Sub1)
<class '__main__.M1'>
已經說明的差異:創建Sub1的時候M1叫,都 類是M1的實例。我在此處使用super()
進行實際創建, 由於稍後將變得清晰的原因。
>>> class M2(type):
>>> def __new__(meta, name, bases, atts):
>>> print "M2 called for " + name
>>> return super(M2, meta).__new__(meta, name, bases, atts)
>>> class C2(object):
>>> __metaclass__ = M2
M2 called for C2
>>> type(C2)
<class '__main__.M2'>
>>> class Sub2(C1, C2):
>>> pass
M1 called for Sub2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 23, in __new__
TypeError: Error when calling the metaclass bases
metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
這是對元繼承多重繼承的主要限制。 Python不知道M1和M2是否是兼容的元類, 因此它會強制你創建一個新元件,以保證它能夠滿足你的需求。
>>> class M3(M1, M2):
>>> def __new__(meta, name, bases, atts):
>>> print "M3 called for " + name
>>> return super(M3, meta).__new__(meta, name, bases, atts)
>>> class C3(C1, C2):
>>> __metaclass__ = M3
M3 called for C3
M1 called for C3
M2 called for C3
>>> type(C3)
<class '__main__.M3'>
這就是爲什麼我在使用元類super()
__new__
功能:左右各一 可以調用MRO下一個。
某些使用情況可能需要你的類是type
類型,或者可能要 避免繼承問題,在這種情況下,元類的功能可能是 的路要走。在其他情況下,類的類型可能真的很重要,或者您可能希望對所有的子類進行操作,在這種情況下,子類化 type
將是一個更好的主意。隨意使用任何特定情況下最適合 的款式。
感謝您花時間解釋這一點。 –
非常感謝,我很少看到這樣一個明確的答案。 – Nikwin