Frage

Ich habe eine class X, die aus einer Klasse mit einer eigenen metaclass Meta ableitet. Ich möchte auch derive X aus der deklarativen Basis in SQL Alchemy. Aber ich kann das einfach nicht tun

def class MyBase(metaclass = Meta):
    #...

def class X(declarative_base(), MyBase):
    #...

da ich metaclass Konflikt Fehler bekommen würde: ‚die Metaklasse einer abgeleiteten Klasse muss eine (nicht streng) Unterklasse der metaclasses aller seiner Basen sein.‘ Ich verstehe, dass ich eine neue Metaklasse erstellen müssen, die von beiden Meta ableiten würde und von was auch immer Metaklasse die deklarative Basis verwendet (DeclarativeMeta ich denke?). So ist es genug zu schreiben:

def class NewMeta(Meta, DeclarativeMeta): pass
def class MyBase(metaclass = NewMeta):
    #...
def class X(declarative_base(), MyBase):
    #...

Ich habe versucht, und es scheint zu arbeiten; aber ich fürchte, ich mit diesem Code ein Problem eingeführt haben.

habe ich gelesen, das Handbuch, aber es ist ein bisschen zu kryptisch für mich. Was ist

EDIT:

Der Code für meine Klassen verwendet wird, ist wie folgt:

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'
    #...
War es hilfreich?

Lösung

Edit: Jetzt bei IterRegistry und DeclarativeMeta sah zu haben, ich glaube, du bist Code in Ordnung ist

.

IterRegistry definiert __new__ und __iter__, während DeclarativeMeta definiert __init__ und __setattr__. Da es keine Überlappung gibt, gibt es keine direkte Notwendigkeit Anruf super. Trotzdem wäre es gut, dies zu tun, um zukunftssichere Code.


Haben Sie die Kontrolle über die Definition von Meta haben? Können Sie uns ihre Definition zeigen? Ich glaube nicht, können wir sagen, es funktioniert oder nicht funktioniert, wenn wir die Definition von Meta sehen.

Zum Beispiel gibt es ein potenzielles Problem, wenn Ihr Meta nicht Anruf tut super(Meta,cls).__init__(classname, bases, dict_)

Wenn Sie diesen Code ausführen

class DeclarativeMeta(type):
    def __init__(cls, classname, bases, dict_):
        print('DeclarativeMeta')
        # if '_decl_class_registry' in cls.__dict__:
        #     return type.__init__(cls, classname, bases, dict_)       
        # _as_declarative(cls, classname, dict_)
        return type.__init__(cls, classname, bases, dict_)

class Meta(type):
    def __init__(cls, classname, bases, dict_):
        print('Meta')
        return type.__init__(cls, classname, bases, dict_)

class NewMeta(Meta,DeclarativeMeta): pass

class MyBase(object):
    __metaclass__ = NewMeta
    pass

Dann wird nur die Zeichenfolge 'Meta' wird gedruckt. Mit anderen Worten wird nur Meta.__init__ laufen. DeclarativeMeta.__init__ bekommt übersprungenen.

Auf der anderen Seite, wenn Sie definieren

class Meta(type):
    def __init__(cls, classname, bases, dict_):
        print('Meta')
        return super(Meta,cls).__init__(classname, bases, dict_)

Dann werden beide Meta.__init__ und DeclarativeMeta.__init__ wird ausgeführt werden.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top