有细微的差异,主要与继承有关。当使用
作为元类,结果类实际上是
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'>
这就是我为什么用
超级()
在元类中
__new__
功能:所以每一个
可以打给MRO的下一个。
某些用例可能需要类的类型
类型
或者可能想要
为了避免继承问题,在这种情况下,元类函数可能是
前进的道路。在其他情况下,班级的类型可能真的很重要,
或者您可能希望对所有子类进行操作,在这种情况下,子类化
类型
会是个更好的主意。请随意使用最适合的款式
任何特定情况。