J'ai un class X
qui dérive d'une classe avec sa propre métaclasse Meta
. Je veux aussi dériver X de la base déclarative dans SQL Alchemy. Mais je ne peux pas faire simpleTraiter le conflit de métaclasses avec la base déclarative SQL Alchemy
def class MyBase(metaclass = Meta):
#...
def class X(declarative_base(), MyBase):
#...
depuis que je recevrais erreur métaclasse conflit: la métaclasse d'une classe dérivée doit être un (non stricte) sous-classe des métaclasses de toutes ses bases. Je comprends que j'ai besoin de créer une nouvelle métaclasse qui dériverait à la fois de Meta et de la métaclasse que la base déclarative utilise (DeclarativeMeta je pense?). Alors, est-ce suffisant pour écrire:
def class NewMeta(Meta, DeclarativeMeta): pass
def class MyBase(metaclass = NewMeta):
#...
def class X(declarative_base(), MyBase):
#...
J'ai essayé, et il semble travailler; mais j'ai peur d'avoir introduit un problème avec ce code. Je lis le manuel, mais c'est un peu trop énigmatique pour moi. Qu'est-ce
EDIT:
Le code utilisé pour mes classes est la suivante:
class IterRegistry(type):
def __new__(cls, name, bases, attr):
attr['_registry'] = {}
attr['_frozen'] = False
print(name, bases)
print(type(cls))
return type.__new__(cls, name, bases, attr)
def __iter__(cls):
return iter(cls._registry.values())
class SQLEnumMeta(IterRegistry, DeclarativeMeta): pass
class EnumType(metaclass = IterRegistry):
def __init__(self, token):
if hasattr(self, 'token'):
return
self.token = token
self.id = len(type(self)._registry)
type(self)._registry[token] = self
def __new__(cls, token):
if token in cls._registry:
return cls._registry[token]
else:
if cls._frozen:
raise TypeError('No more instances allowed')
else:
return object.__new__(cls)
@classmethod
def freeze(cls):
cls._frozen = True
def __repr__(self):
return self.token
@classmethod
def instance(cls, token):
return cls._registry[token]
class C1(Base, EnumType, metaclass = SQLEnumMeta):
__tablename__ = 'c1'
#...
Merci. J'ai négligé ce problème précis. J'ai ajouté les détails dans ma question, mais il semble que les choses deviennent trop compliquées à ce stade .. – max
Merci. Je vais remplacer 'return type .__ new __ (cls, nom, bases, attr)' par 'return super() .__ nouveau __ (cls, nom, bases, attr)'. Bien qu'il ne soit pas infaillible, au moins c'est un peu mieux que d'espérer qu'il n'y a pas de __new__ dans la base déclarative.Certes, tout cet héritage multiple est très dangereux, puisque personne ne fait de contrat précis sur le comportement ... – max
L'héritage multiple est généralement correct (en Python). Mais l'héritage multiple des classes qui sont des instances de métaclasses différentes est difficile, avec de bonnes raisons (c'est pourquoi il existe une règle sur la fusion explicite de métaclasses). Nous pouvons comprendre ce qui signifierait que quelque chose soit un cheval et un oiseau (même si nous n'en avons jamais vu), mais il est beaucoup plus difficile de voir ce que «être un cheval et une bonne idée» pourrait signifier. :-RÉ – Veky