2010-06-09 11 views
56

Warum ist das:Metaclass Mehrfachvererbung Inkonsistenz

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

in Ordnung, und wie erwartet funktioniert:

created <class '__main__.MyMixin'> 
created <class '__main__.MyList'> 

Aber:

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

ist nicht in Ordnung, und sprengt thusly ?:

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 

Antwort

81

Es ist kein custom-Metaklasse Problem (obwohl es bei metaclass Stadium diagnostiziert ist):

>>> 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 

und das Problem ist nur das gleiche wie diese:

>>> 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 

dh kann nicht multiplizieren erben von einer Basisklasse, gefolgt von einer abgeleiteten Klasse - es ist unmöglich, eine konsistente MRO zu definieren, die die üblichen MRO-Einschränkungen/Garantien erfüllt.

Zum Glück, nicht wahr will, das zu tun - die Unterklasse vermutlich eine Methode der Basisklasse überschreibt (das ist, was normale Subklassen tun ;-), und die Basisklasse „vor“ mit würde bedeuten "die Überschreibung wegschatten".

Setzen Sie die Basisklasse nach der abgeleitete ist ziemlich nutzlos, aber zumindest ist es harmlos (und im Einklang mit normalen MRO Garantien).

Ihr erstes Beispiel natürlich funktioniert, weil MyMixin ist nicht von list abgeleitet:

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

... aber es ist von object abgeleitet (wie alle modernen Stil Python-Klasse), so dass die zweites Beispiel kann nicht funktionieren (ziemlich unabhängig von MyMixin mit einer benutzerdefinierten Metaklasse).

-1

Hier erben Sie die Elternklasse, und die Elternklasse erbt bereits eine andere Klasse. Daher muss die Klasse, die die Elternklasse bereits geerbt hat, nicht geerbt werden.

Zum Beispiel:

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

Es wird einen Fehler werfen, weil A die Klasse Object erbt und B die A erbt, so indirekt B Objekt erbt, so gibt es keine Notwendigkeit Objekt zu erben. . . .

Die Lösung besteht darin, nur die Objektklasse aus der Klasse B ... Argumente Liste zu entfernen.