2010-06-09 13 views
56

¿Por qué es esto:MetaClass herencia múltiple inconsistencia

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

bien, y funciona como se esperaba:

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

Pero esto:

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

no está bien, y hace saltar 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 

Respuesta

81

No es un problema a medida metaclase (aunque es diagnosticado en la etapa metaclase):

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

y el problema es lo mismo como éste:

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

es decir, no puede multiplicar hereda de una clase base seguida de una clase derivada; es imposible definir una MRO consistente que satisfaga las restricciones/garantías MRO usuales.

Afortunadamente, usted no querrá a hacer eso - la subclase presumiblemente anula algún método de la clase base (que es lo que hacen las subclases normales ;-), y tener la clase base "delante" sería significa "sombrear la anulación".

Poner la clase base después de la derivada es bastante inútil, pero al menos es inocua (y coherente con las garantías MRO normales).

Su primer ejemplo por supuesto funciona porque MyMixin es no deriva de list:

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

... pero se deriva de object (como cualquier clase de Python-estilo moderno), por lo que la segundo ejemplo no puede funcionar (independientemente de MyMixin teniendo una metaclase personalizada).

-1

Aquí está heredando la clase principal y la clase principal ya está heredando otra clase, por lo que no es necesario heredar la clase que la clase principal ya ha heredado.

Por ejemplo:

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

Se generará un error porque A es heredera de la clase Object y B hereda la A, por lo que indirectamente B hereda objeto, de modo que no hay necesidad de heredar objeto. . . .

La solución es simplemente eliminar la clase de objeto de la clase B ... lista de argumentos.