元类多重继承不一致

Mat*_*son 57 python metaclass

为什么是这样:

class MyType(type):
    def __init__(cls, name, bases, attrs):
        print 'created', cls
class MyMixin:
    __metaclass__ = MyType
class MyList(list, MyMixin): pass
Run Code Online (Sandbox Code Playgroud)

好的,按预期工作:

created <class '__main__.MyMixin'>
created <class '__main__.MyList'>
Run Code Online (Sandbox Code Playgroud)

但是这个:

class MyType(type):
    def __init__(cls, name, bases, attrs):
        print 'created', cls
class MyMixin:
    __metaclass__ = MyType
class MyObject(object, MyMixin): pass
Run Code Online (Sandbox Code Playgroud)

不行,并且如此爆炸?:

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
Run Code Online (Sandbox Code Playgroud)

Ale*_*lli 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
Run Code Online (Sandbox Code Playgroud)

问题和这个问题一样:

>>> 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
Run Code Online (Sandbox Code Playgroud)

即,不能从基类继承乘以派生类 - 不可能定义满足通常的MRO约束/保证的一致MRO.

幸运的是,您不希望这样做 - 子类可能会覆盖基类的某些方法(这是正常的子类所做的 ;-),并且基类"在前面"将意味着"遮蔽覆盖".

将基类放在派生类之后是没用的,但至少它是无害的(并且与正常的MRO保证一致).

你的第一个例子当然是有效的,因为MyMixin不是来自list:

>>> MyMixin.__mro__
(<class '__main__.MyMixin'>, <type 'object'>)
Run Code Online (Sandbox Code Playgroud)

...但它源自object(像每一个现代风格的Python类),所以第二个例子不能(从完全独立工作,MyMixin有一个自定义的元类).