Ich bin auf der Suche nach einer Möglichkeit, die Klassenerstellung abzuschließen, um __qualname__
in Python vor 3.3 neu zu erstellen. Meine Metaklasse QualNameMeta
rekursiv setzt __qualname__
und propagiert es an Mitglieder. Aufgrund der Funktionsweise müsste ich eine Funktion ausführen, wenn die Klasse dem Modul hinzugefügt wird.Finalisieren Sie die Klasse, nachdem sie an den Modul-Namespace gebunden ist
Da Funktionen nicht aktiv teilnehmen, muss ich das Ergebnis testen, um nicht erreichbare Namen zu markieren.
class Scope1(object):
__metaclass__ = QualNameMeta
def scope_f(self):
class ScopeF(object):
__metaclass__ = QualNameMeta
return ScopeF
print scope_f.__qualname__ # gives correct Scope1.scope_f
print scope_f().__qualname__ # gives ScopeF, should be None or Scope1.scope_f.<locals>.ScopeF
Dieser Test kann leicht nach Erstellung (ohne Abwickeln Magie) durchgeführt werden:
def test_qualname(obj):
namespace = sys.modules[obj.__module__]
for name in obj.__qualname__.split('.'):
try:
namespace = getattr(namespace, name)
except AttributeError: # name does not point to any object
return False
return namespace is obj # make sure we got the right one
Allerdings kann ich das nicht bekommen direkt von der Metaklasse zu arbeiten. Wenn ich test_qualname
in QualMeta.__new__
oder QualMeta.__init__
rufe, ist das Objekt noch nicht an das Modul gebunden. Also, ich brauche einen Weg, um die Prüfung nach das Objekt ist an das Modul gebunden durchzuführen.
Warum nicht Dekorateure? Ich muss dies dauerhaft mit Vererbung arbeiten, so dass eine gesamte Klassenhierarchie gepatcht werden kann, indem nur die Basisklasse geändert wird. Die Verwendung einer Metaklasse ist die einzige Lösung, die ich bisher gefunden habe.
Ein minimales Blind Beispiel:
class QualMeta(type):
def __new__(mcs, name, bases, class_dict):
new_cls = type.__new__(mcs, name, bases, class_dict)
new_cls.__qualname__ = name # dummy for top-level only
if not test_qualname(new_cls): # new_cls is not bound yet, test will fail
new_cls.__qualname__ = None
return new_cls
class Qualnamed(object):
__metaclass__ = QualMeta
print(Qualnamed.__qualname__) # gives None
Das Problem Bindung '__qualname__ nicht 'to' new_cls' würde sonst ein AttributeError sein. Das Problem ist, dass 'new_cls' zu diesem Zeitpunkt nicht an sein Modul gebunden ist. Daher ist 'new_cls.__qualname__' definiert und gültig, aber das Nachschlagen in seinem Modul schlägt fehl. – MisterMiyagi
Entschuldigung, lesen Sie die Frage zu schnell. Da die Metaklasse grundsätzlich die Klasse erstellt, ist es normal, dass Sie 'QualMeta' nicht in' module' oder 'globals' sehen, da es noch nicht existiert. – Cyrbil