Resolviendo conflictos de metaclase

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

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 

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 debe ser reelaborado 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 "", 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 # 

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

Para usar el patrón descrito por @michael, pero con compatibilidad con Python 2 y 3 (usando 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 syntax de metaclase específica de la versión, metaclass_resolver funciona con Python 2 y Python 3.

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