Pregunta

¿Por qué es esto:

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

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 así:?

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
¿Fue útil?

Solución

No es un problema a medida metaclase (aunque de 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 pueden heredar multiplican de una clase base, seguido de una clase derivada - es imposible definir un MRO consistente que satisface las limitaciones habituales de MRO / garantías

.

Afortunadamente, no lo hace quieren para hacer eso - la subclase presumiblemente anula algún método de la clase base (que es lo subclases normales lo ;-), y que tiene la clase base "delante" significaría "sombreado la anulación de distancia".

Poner la clase base después la deriva uno es bastante inútil, pero al menos es inocuo (y consistente con garantías de MRO normales).

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

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

... pero es derivado de object (como cada estilo moderno clase de Python), por lo que el segundo ejemplo no se puede trabajar (con bastante independencia de MyMixin tener una metaclase personalizado).

Otros consejos

A continuación, se hereda la clase padre, y la clase padre ya se ha heredado otra clase, por lo que no hay necesidad de heredar la clase que la clase padre ya se hereda.

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, lo que no hay necesidad de objeto hereda. . . .

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top