元类多重继承不一致性
为什么这个:
class MyType(type):
def __init__(cls, name, bases, attrs):
print 'created', cls
class MyMixin:
__metaclass__ = MyType
class MyList(list, MyMixin): pass
是可以的,并且按预期工作:
created <class '__main__.MyMixin'>
created <class '__main__.MyList'>
但是这个:
class MyType(type):
def __init__(cls, name, bases, attrs):
print 'created', cls
class MyMixin:
__metaclass__ = MyType
class MyObject(object, MyMixin): pass
就不行了,结果是这样崩溃的?:
created <class '__main__.MyMixin'>
Traceback (most recent call last):
File "/tmp/junk.py", line 11, in <module>
class MyObject(object, MyMixin): pass
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases object, MyMixin
2 个回答
-1
在这里,你是从父类继承的,而这个父类已经继承了另一个类,所以你不需要再去继承父类已经继承的那个类。
举个例子:
class A(object):
.
.
class B(object, A):
.
.
这样会报错,因为A类继承了Object类,而B类又继承了A类,所以B类间接地也继承了Object类,因此没有必要再去继承Object类。
解决办法就是直接把B类中的Object类从继承列表中去掉就可以了。
83
这不是一个自定义元类的问题(虽然在元类阶段会被“诊断”出来):
>>> class Normal(object): pass
...
>>> class MyObject(object, Normal): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases object, Normal
而且这个问题和这个是一样的:
>>> class Derived(Normal): pass
...
>>> class Ok(Derived, Normal): pass
...
>>> class Nope(Normal, Derived): pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
Cannot create a consistent method resolution
order (MRO) for bases Normal, Derived
也就是说,不能从一个基类和一个派生类同时继承——这会导致无法定义一个一致的MRO(方法解析顺序),来满足通常的MRO约束和保证。
幸运的是,你其实并不想这样做——子类通常会覆盖基类的某个方法(这就是正常子类的“职责”;-),如果基类在前面,就意味着会“遮住”这个覆盖。
把基类放在派生类后面其实没什么用,但至少这样做是无害的(并且符合正常的MRO保证)。
你的第一个例子当然可以工作,因为 MyMixin
并不是从 list
继承的:
>>> MyMixin.__mro__
(<class '__main__.MyMixin'>, <type 'object'>)
……但它确实是从 object
继承的(就像每个现代风格的Python类一样),所以第二个例子就无法工作了(这和 MyMixin
是否有自定义元类无关)。