Gibt es in Python 2.5 eine Möglichkeit, einen Dekorator zu erstellen, der eine Klasse dekoriert? Insbesondere möchte ich einen Dekorator verwenden, um ein Element zu einer Klasse hinzuzufügen und den Konstruktor so zu ändern, dass er einen Wert für dieses Mitglied annimmt.
Suchen Sie nach etwas wie dem folgenden (das einen Syntaxfehler in 'class Foo:' hat:):
def getId(self): return self.__id
class addID(original_class):
def __init__(self, id, *args, **kws):
self.__id = id
self.getId = getId
original_class.__init__(self, *args, **kws)
@addID
class Foo:
def __init__(self, value1):
self.value1 = value1
if __name__ == '__main__':
foo1 = Foo(5,1)
print foo1.value1, foo1.getId()
foo2 = Foo(15,2)
print foo2.value1, foo2.getId()
Ich denke, was ich wirklich will, ist eine Möglichkeit, so etwas wie eine C # -Schnittstelle in Python zu machen. Ich muss wohl mein Paradigma wechseln.
quelle
Abgesehen von der Frage, ob Klassendekorateure die richtige Lösung für Ihr Problem sind:
In Python 2.6 und höher gibt es Klassendekoratoren mit der @ -syntax, sodass Sie schreiben können:
In älteren Versionen können Sie dies auf andere Weise tun:
Beachten Sie jedoch, dass dies genauso funktioniert wie für Funktionsdekorateure und dass der Dekorateur die neue (oder geänderte Original-) Klasse zurückgeben sollte, was im Beispiel nicht der Fall ist. Der addID-Dekorator würde folgendermaßen aussehen:
Sie können dann die entsprechende Syntax für Ihre Python-Version wie oben beschrieben verwenden.
Aber ich stimme anderen zu, dass Vererbung besser geeignet ist, wenn Sie überschreiben möchten
__init__
.quelle
Niemand hat erklärt, dass Sie Klassen dynamisch definieren können. Sie können also einen Dekorateur haben, der eine Unterklasse definiert (und zurückgibt):
Was in Python 2 verwendet werden kann (der Kommentar von Blckknght, der erklärt, warum Sie dies in 2.6+ fortsetzen sollten) wie folgt:
Und in Python 3 so (aber seien Sie vorsichtig, wenn Sie es
super()
in Ihren Klassen verwenden):So können Sie Ihren Kuchen haben und ihn essen - Erbe und Dekorateure!
quelle
super
Aufrufe in der ursprünglichen Klasse unterbrochen werden . WennFoo
eine Methode mit dem Namenfoo
aufgerufen wordensuper(Foo, self).foo()
wäre, würde sie sich unendlich wiederholen, da der NameFoo
an die vom Dekorateur zurückgegebene Unterklasse gebunden ist, nicht an die ursprüngliche Klasse (auf die unter keinem Namen zugegriffen werden kann). Die Argumentation von Python 3super()
vermeidet dieses Problem (ich gehe davon aus, dass es über dieselbe Compiler-Magie funktioniert, mit der es überhaupt funktioniert). Sie können das Problem auch umgehen, indem Sie die Klasse manuell unter einem anderen Namen dekorieren (wie im Python 2.5-Beispiel).Das ist keine gute Praxis und deshalb gibt es keinen Mechanismus, um dies zu tun. Der richtige Weg, um das zu erreichen, was Sie wollen, ist die Vererbung.
Schauen Sie sich die Klassendokumentation an .
Ein kleines Beispiel:
Auf diese Weise hat Boss alles
Employee
, auch seine eigene__init__
Methode und seine eigenen Mitglieder.quelle
Ich würde zustimmen, dass Vererbung besser zu dem gestellten Problem passt.
Ich fand diese Frage allerdings sehr praktisch beim Dekorieren von Kursen, danke an alle.
Hier sind einige weitere Beispiele, die auf anderen Antworten basieren, einschließlich der Auswirkungen der Vererbung auf Python 2.7 (und @wraps , das die Dokumentzeichenfolge der ursprünglichen Funktion usw. beibehält):
Oft möchten Sie Ihrem Dekorateur Parameter hinzufügen:
Ausgänge:
Ich habe einen Funktionsdekorateur verwendet, da ich sie prägnanter finde. Hier ist eine Klasse zum Dekorieren einer Klasse:
Eine robustere Version, die nach diesen Klammern sucht und funktioniert, wenn die Methoden für die dekorierte Klasse nicht vorhanden sind:
Die
assert
Kontrollen , dass der Dekorateur nicht ohne Klammern verwendet. Wenn dies der Fall ist, wird die zu dekorierende Klasse an denmsg
Parameter des Dekorators übergeben, wodurch ein ausgelöst wirdAssertionError
.@decorate_if
gilt nurdecorator
wenn dascondition
ausgewertet wirdTrue
.Die
getattr
,callable
test und@decorate_if
werden verwendet, damit der Dekorator nicht kaputt geht, wenn diefoo()
Methode für die zu dekorierende Klasse nicht vorhanden ist.quelle
Hier gibt es tatsächlich eine ziemlich gute Implementierung eines Klassendekorateurs:
https://github.com/agiliq/Django-parsley/blob/master/parsley/decorators.py
Ich denke tatsächlich, dass dies eine ziemlich interessante Implementierung ist. Da es die Klasse, die es dekoriert, unterordnet, verhält es sich in Dingen wie
isinstance
Prüfungen genau wie diese Klasse .__init__
Dies hat einen zusätzlichen Vorteil: Es ist nicht ungewöhnlich, dass die Anweisung in einem benutzerdefinierten Django-Formular Änderungen oder Ergänzungen vornimmt,self.fields
sodass Änderungen besser vorgenommen werden könnenself.fields
, nachdem alle__init__
für die betreffende Klasse ausgeführt wurden.Sehr schlau.
In Ihrer Klasse möchten Sie jedoch, dass die Dekoration den Konstruktor ändert, was meiner Meinung nach kein guter Anwendungsfall für einen Klassendekorateur ist.
quelle
Hier ist ein Beispiel, das die Frage der Rückgabe der Parameter einer Klasse beantwortet. Darüber hinaus wird die Vererbungskette weiterhin berücksichtigt, dh es werden nur die Parameter der Klasse selbst zurückgegeben. Die Funktion
get_params
wird als einfaches Beispiel hinzugefügt, aber dank des Inspect-Moduls können auch andere Funktionen hinzugefügt werden.quelle
Django hat
method_decorator
einen Dekorateur, der jeden Dekorateur in einen Methodendekorateur verwandelt. Sie können sehen, wie er implementiert wird indjango.utils.decorators
:https://github.com/django/django/blob/50cf183d219face91822c75fa0a15fe2fe3cb32d/django/utils/decorators.py#L53
https://docs.djangoproject.com/de/3.0/topics/class-based-views/intro/#decorating-the-class
quelle