2016-04-21 3 views
0

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 

Antwort

0

Sie benötigen eine neues Attribut in class_dict setzen und lassen type.__new__() die Bindung tun:

class QualMeta(type): 
    def __new__(mcs, name, bases, class_dict): 
     class_dict['__qualname__'] = name 
     new_cls = type.__new__(mcs, name, bases, class_dict) 
     return new_cls 

class Qualnamed(object): 
    __metaclass__ = QualMeta 

print(Qualnamed.__qualname__) # print "Qualnamed" 
+0

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

+0

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

Verwandte Themen