So habe ich diese Metaklasse, die ich für die automatische Registrierung von neuen Komponenten, dh Unterklassen einer Basiskomponente verwenden möchte Klasse. Beim Registrieren einer neuen Komponente wird erwartet, dass die Instanz an die register_component()-Funktion übergeben wird, die das verarbeitet.Das Instanziieren einer gerade erstellten Klasse in einer Metaklasse führt zu einem RuntimeError ("super(): empty __class__ cell")
Metaclass Code (abgespeckte Version):
class AutoRegisteredMeta(type):
def __new__(metacls, name, bases, attrs):
# ... (omitted) check if "name" has already been registered ...
new_class = super().__new__(metacls, name, bases, attrs)
register_component(name, new_class()) # RuntimeError(super(): empty __class__ cell)
return new_class
Das Problem ist, dass new_class()
führt zu einem Fehler aufgerufen wird - aber nicht für alle Klassen. Nach einigen Experimenten wurde mir klar, dass dies nur passiert, wenn eine Unterklasse super().__init__()
in ihrer eigenen __init__()
Methode aufruft.
Probenkomponente und die Basisklasse:
class BaseComponent(metaclass=AutoRegisteredMeta):
def __init__(self):
# do some work here ...
class ComponentFoo(BaseComponent):
def __init__(self):
super().__init__() # <--- RuntimeError occurs here
self.foo = 'bar'
Was mache ich hier falsch? Reading this Ich fand heraus, dass ich wahrscheinlich nicht Instanziierung in metaclass'es __new__()
oder __init__()
tun sollte, richtig? Kann das vielleicht irgendwie umgangen werden?
Auch einige Erklärung in Laien wäre nett, ich weiß nicht viel von den Interna der CPython-Implementierung.
Vielen Dank im Voraus!
(FWIW, verwende ich Python 3.3.6, Ubuntu)
EDIT: Ich füge die minimale Beispiel, das angefordert wurde, können Sie es direkt ausführen und die Fehler in Aktion selbst sehen.
#!/usr/bin/env python3
class AutoRegisteredMeta(type):
def __new__(metacls, name, bases, attrs):
new_class = super().__new__(metacls, name, bases, attrs)
new_class() # <--- RuntimeError can occur here
return new_class
class BaseComponent(metaclass=AutoRegisteredMeta):
def __init__(self):
print("BaseComponent __init__()")
class GoodComponent(BaseComponent):
def __init__(self):
print("GoodComponent __init__()")
class BadComponent(BaseComponent):
def __init__(self):
print("BadComponent __init__()")
super().__init__() # <--- RuntimeError occurs because of this
Ihr eigentlich Registrierungscode eine Instanz der Klasse instanziiert, bevor die Metaklasse beendet hat. 'register_component (name, new_class)' könnte besser sein. –
Könnten Sie das in ein [minimales Beispiel] (http://stackoverflow.com/help/mcve) reorganisieren, das tatsächlich ausgeführt wird (einschließlich 'register_component',' BaseComponent .__ init__', ...)? – jonrsharpe
@CharlieClark Ja, ich weiß, das ist genau das Problem. Das ließ mich denken, dass es besser wäre, die Klasse selbst als ihre Instanz zu registrieren, was auch Sie in Ihrem Kommentar vorgeschlagen haben. Die Registrierung einer Komponenteninstanz entspricht der aktuellen Vorgehensweise im Rest des Systems. :) – plamut