method example python python-3.x multiple-inheritance metaclass

python - example - Resolviendo conflictos de metaclase



python abstract class example (5)

El ejemplo que utiliza sqlite3 no es válido porque es un módulo y no una clase. También he encontrado este problema.

Aquí está su problema: La clase base tiene una metaclase que no es del mismo tipo que la subclase. Es por eso que obtienes un TypeError .

Usé una variación de este fragmento de activestate usando noconflict.py . El fragmento de código se debe volver a trabajar, ya que no es compatible con Python 3.x. En cualquier caso, debería darle una idea general.

Fragmento de problema

class M_A(type): pass class M_B(type): pass class A(object): __metaclass__=M_A class B(object): __metaclass__=M_B class C(A,B): pass #Traceback (most recent call last): # File "<stdin>", line 1, in ? #TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass #of the metaclasses of all its bases

Fragmento de solución

from noconflict import classmaker class C(A,B): __metaclass__=classmaker() print C #<class ''C''>

La receta del código resuelve adecuadamente las metaclases por ti.

Necesito crear una clase que use una clase base diferente dependiendo de alguna condición. Con algunas clases me sale el infame:

TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases

Un ejemplo es sqlite3 , aquí hay un pequeño ejemplo que puede usar en el intérprete:

>>> import sqlite3 >>> x = type(''x'', (sqlite3,), {}) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases


En lugar de usar la receta como lo menciona jdi, puede usar directamente:

class M_C(M_A, M_B): pass class C(A, B): __metaclass__ = M_C


Esto también sucede cuando intentas heredar de una función y no de una clase.

P.ej.

def function(): pass class MyClass(function): pass


Para usar el patrón descrito por @michael, pero con compatibilidad con Python 2 y 3 (utilizando la biblioteca de six ):

from six import with_metaclass class M_C(M_A, M_B): pass class C(with_metaclass(M_C, A, B)): # implement your class here


Por lo que entendí de las respuestas anteriores, lo único que normalmente tenemos que hacer manualmente es:

class M_A(type): pass class M_B(type): pass class A(metaclass=M_A): pass class B(metaclass=M_B): pass class M_C(M_A, M_B): pass class C:(A, B, metaclass=M_C): pass

Pero podemos automatizar las dos últimas líneas ahora por:

def metaclass_resolver(*classes): metaclass = tuple(set(type(cls) for cls in classes)) metaclass = metaclass[0] if len(metaclass)==1 / else type("_".join(mcls.__name__ for mcls in metaclass), metaclass, {}) # class M_C return metaclass("_".join(cls.__name__ for cls in classes), classes, {}) # class C class C(metaclass_resolver(A, B)): pass

Dado que no utilizamos ninguna sintaxis de metaclase específica de la versión, metaclass_resolver funciona con Python 2 y con Python 3.