La résolution des conflits métaclasse
je dois créer une classe qui utilise une classe de base différente en fonction de certaines conditions. Avec certaines classes, j'obtiens l'infâme:
TypeError: metaclass conflict: the metaclass of a derived class must be a (non-strict) subclass of the metaclasses of all its bases
Un exemple sqlite3
, voici un court exemple vous pouvez même l'utiliser dans l'interpréteur:
>>> 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
5 réponses
au Lieu d'utiliser la recette comme indiqué par jdi, vous pouvez utiliser directement:
class M_C(M_A, M_B):
pass
class C(A, B):
__metaclass__ = M_C
votre exemple en utilisant sqlite3
est invalide car il s'agit d'un module et non d'une classe. J'ai également rencontré ce problème.
Heres votre problème: La classe de base a une métaclasse qui n'est pas du même type que la sous-classe. C'est pourquoi vous obtenez une TypeError
.
j'ai utilisé une variation de cet extrait d'activation utilisant noconflict.py. Le snippet doit être retravaillé car il n'est pas python 3.x compatible. De même, il devrait vous donner un général idée.
Problème extrait de
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
Solution de l'extrait de code
from noconflict import classmaker
class C(A,B):
__metaclass__=classmaker()
print C
#<class 'C'>
la recette du code résout correctement les métaclasses pour vous.
pour utiliser le modèle décrit par @michael, mais avec la compatibilité Python 2 et 3 (en utilisant le six
bibliothèque):
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
d'après ce que j'ai compris des réponses précédentes, le seul que nous ayons à faire manuellement est:
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
Mais nous pouvons automatiser les deux dernières lignes par:
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
puisque nous n'utilisons pas de syntaxe metaclass spécifique à la version, ceci metaclass_resolver
fonctionne avec Python 2 et Python 3.
Cela se produit également lorsque vous essayez d'hériter d'une fonction et non une classe.
par exemple.
def function():
pass
class MyClass(function):
pass