Hallo, ich habe ungefähr so etwas wie das Folgende. Grundsätzlich muss ich von einem Dekorator, der für die Instanzmethode in ihrer Definition verwendet wird, auf die Klasse einer Instanzmethode zugreifen.
def decorator(view):
# do something that requires view's class
print view.im_class
return view
class ModelA(object):
@decorator
def a_method(self):
# do some stuff
pass
Der Code wie er ist gibt:
AttributeError: 'function' object has no attribute 'im_class'
Ich habe ähnliche Fragen / Antworten gefunden - Python Decorator lässt die Funktion vergessen, dass sie zu einer Klasse gehört, und Get Class in Python Decorator - aber diese basieren auf einer Problemumgehung, die die Instanz zur Laufzeit erfasst, indem der erste Parameter abgerufen wird. In meinem Fall rufe ich die Methode basierend auf den Informationen auf, die aus ihrer Klasse stammen, sodass ich nicht warten kann, bis ein Aufruf eingeht.
inspect.getmro(cls)
, um alle Basisklassen im Klassendekorator zu verarbeiten, um die Vererbung zu unterstützen.inspect
nach dem Rescue Stackoverflow.com/a/1911287/202168 ausSeit Python 3.6 können Sie
object.__set_name__
dies auf sehr einfache Weise erreichen. Das Dokument gibt an, dass__set_name__
"zum Zeitpunkt der Erstellung des Besitzers der besitzenden Klasse aufgerufen wird". Hier ist ein Beispiel:Beachten Sie, dass es zur Zeit der Klassenerstellung aufgerufen wird:
Wenn Sie mehr darüber erfahren möchten, wie Klassen erstellt werden und insbesondere wann genau
__set_name__
aufgerufen wird, lesen Sie die Dokumentation zum Thema "Erstellen des Klassenobjekts" .quelle
@class_decorator('test', foo='bar')
def decorator(*args, **kwds): class Descriptor: ...; return Descriptor
__set_name__
Ich wusste es nicht, obwohl ich Python 3.6+ schon lange benutze.hello
keine Methode ist, sondern ein Objekt vom Typclass_decorator
.if TYPE_CHECKING
, umclass_decorator
als normalen Dekorateur den richtigen Typ zurückzugeben.Wie andere bereits betont haben, wurde die Klasse zum Zeitpunkt des Aufrufs des Dekorateurs noch nicht erstellt. Jedoch ist es möglich , die Funktion Objekt mit den decorator Parametern mit Anmerkungen zu versehen, dann die Funktion in der der Metaklasse Wieder dekoriert
__new__
Methode. Sie müssen__dict__
direkt auf das Attribut der Funktion zugreifen , was zumindest für michfunc.foo = 1
zu einem AttributeError geführt hat.quelle
setattr
sollte verwendet werden, anstatt zuzugreifen__dict__
Wie Mark vorschlägt:
Dieser Code zeigt, wie dies mit der automatischen Nachbearbeitung funktionieren kann:
Die Ausgabe ergibt:
Beachten Sie, dass in diesem Beispiel:
Hoffe das hilft
quelle
Wie Ants angegeben hat, können Sie innerhalb der Klasse keinen Verweis auf die Klasse erhalten. Wenn Sie jedoch zwischen verschiedenen Klassen unterscheiden möchten (ohne das eigentliche Klassentypobjekt zu manipulieren), können Sie für jede Klasse eine Zeichenfolge übergeben. Sie können dem Dekorateur auch beliebige andere Parameter mit Dekoratoren im Klassenstil übergeben.
Drucke:
Außerdem sehen Bruce Eckel Seite auf Dekorateure.
quelle
@decorator('Bar')
im Gegensatz zu@Decorator('Bar')
.Was flaschen nobel tut , ist eine temporäre Cache erstellen , dass es auf der Methode speichert, verwendet es etwas anderes (die Tatsache , dass Flask werden die Klassen mit einem Register
register
Klassenmethode) , um tatsächlich die Methode wickelt.Sie können dieses Muster wiederverwenden, diesmal mithilfe einer Metaklasse, damit Sie die Methode beim Import umbrechen können.
In der tatsächlichen Klasse (Sie können dasselbe mit einer Metaklasse tun):
Quelle: https://github.com/apiguy/flask-classy/blob/master/flask_classy.py
quelle
Das Problem ist, dass die Klasse noch nicht existiert, wenn der Dekorateur aufgerufen wird. Versuche dies:
Dieses Programm gibt Folgendes aus:
Wie Sie sehen, müssen Sie einen anderen Weg finden, um das zu tun, was Sie wollen.
quelle
Hier ist ein einfaches Beispiel:
Die Ausgabe ist:
quelle
Dies ist eine alte Frage, die aber auf Venus gestoßen ist. http://venusian.readthedocs.org/en/latest/
Es scheint die Fähigkeit zu haben, Methoden zu dekorieren und Ihnen dabei Zugriff auf die Klasse und die Methode zu gewähren. Beachten Sie, dass das Aufrufen
setattr(ob, wrapped.__name__, decorated)
nicht die typische Art der Verwendung von Venusian ist und den Zweck etwas zunichte macht.So oder so ... das folgende Beispiel ist vollständig und sollte ausgeführt werden.
quelle
Die Funktion weiß nicht, ob es sich um eine Methode am Definitionspunkt handelt, wenn der Dekorationscode ausgeführt wird. Nur wenn auf ihn über die Klassen- / Instanzkennung zugegriffen wird, kann er seine Klasse / Instanz kennen. Um diese Einschränkung zu überwinden, können Sie nach Deskriptorobjekt dekorieren, um den tatsächlichen Dekorationscode bis zur Zugriffs- / Anrufzeit zu verzögern:
Auf diese Weise können Sie einzelne (statische | Klassen-) Methoden dekorieren:
Jetzt können Sie Dekorationscode für die Selbstbeobachtung verwenden ...
... und zur Änderung des Funktionsverhaltens:
quelle
</sigh>
Wie andere Antworten gezeigt haben, ist Decorator eine funktionale Sache. Sie können nicht auf die Klasse zugreifen, zu der diese Methode gehört, da die Klasse noch nicht erstellt wurde. Es ist jedoch völlig in Ordnung, einen Dekorator zu verwenden, um die Funktion zu "markieren" und dann Metaklassentechniken zu verwenden, um später mit der Methode umzugehen, da
__new__
die Klasse zu diesem Zeitpunkt von ihrer Metaklasse erstellt wurde.Hier ist ein einfaches Beispiel:
Wir verwenden
@field
, um die Methode als spezielles Feld zu markieren und sie in der Metaklasse zu behandeln.quelle
if inspect.isfunction(v) and getattr(k, "is_field", False):
Es solltegetattr(v, "is_field", False)
stattdessen sein.Sie haben Zugriff auf die Klasse des Objekts, für das die Methode in der dekorierten Methode aufgerufen wird, die Ihr Dekorator zurückgeben soll. Wie so:
Mit Ihrer ModelA-Klasse können Sie Folgendes tun:
quelle