2010-06-09 44 views
56

爲什麼是這樣的:元類多重繼承不一致

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 

回答

81

這不是一個自定義元類的問題(儘管它在元類階段診斷):

>>> 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保證一致)。

你當然第一個例子工程,因爲MyMixinlist得出:

>>> MyMixin.__mro__ 
(<class '__main__.MyMixin'>, <type 'object'>) 

...但它object衍生(像每一個現代風格的Python類),所以第二個例子不能工作(完全獨立於具有自定義元類的MyMixin)。

-1

在這裏,您繼承父類,並且父類已經繼承另一個類,因此不需要繼承父類已經繼承的類。

例如:

class A(object): 
. 
. 
class B(object, A): 
. 
. 

因爲A被繼承的對象類和B被繼承A,所以間接B被繼承的對象,所以沒有必要繼承對象將拋出異常。 。 。 。

解決方案是從類B ...參數列表中刪除對象類。