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
29
demandé sur NirIzr 2012-06-30 21:15:39

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
15
répondu Michael 2012-12-01 16:22:08

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.

12
répondu jdi 2018-04-03 11:41:19

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
8
répondu Danilo Bargen 2015-10-12 12:34:05

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.

3
répondu Chickenmarkus 2017-01-09 08:32:34

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
0
répondu Antwan 2018-05-01 15:10:24