Python: die statische variable Dekorateur
Ich würde gern ein Dekorateur wie unten, aber ich kann nicht scheinen zu denken, dass der eine Implementierung, die funktioniert. Ich fange an zu denken, es ist nicht möglich, aber dachte, ich würde Sie bitten, Jungs, die erste.
Ich fest: es gibt verschiedene andere Möglichkeiten zum erstellen von statischen Variablen in Python, aber ich finde diese Weise hässlich. Ich möchte wirklich verwenden Sie die folgende syntax, wenn möglich.
@static(x=0)
def f():
x += 1
print x
f() #prints 1
f() #prints 2
I don ' T care wenn die Umsetzung von static
oder lang ist hackity, solange es funktioniert wie oben.
Habe ich diese version, aber es erlaubt nur eine <function>.<varname>
syntax, die bekommt schwerfällig ziemlich schnell mit mehr Funktions-und Variablennamen.
def static(**assignments):
def decorate(func):
for var, val in assignments.items():
setattr(func, var, val)
return func
return decorate
Verschiedenen Dinge, die ich dachte, konnte Sie aber nicht bekommen, um zu arbeiten waren:
- Ändern von f (der dekorierten Funktion) in einer callable Klasse, und irgendwie Speicherung der statischen vars in
self
transparent. - Änderung der globals von f() in der decorator und irgendwie einfügen "global x" - Anweisungen in den code für f.
- Ändern f in einen generator, wo wir binden die Variablen von hand und dann führen Sie das f-code direkt.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Hier ist ein Dekorator, das scheint zu funktionieren.
Beachten Sie, dass dies erfordert die Rücksendung einheimischen() am Ende der Funktion wegen, nicht einheimischen von außen (ich habe nicht viel Erfahrung im Programmieren, so dass wenn es einen Weg gibt, ich kenne es nicht).
Die Ausgabe wäre:
EDIT:
Fand ich etwas zu http://code.activestate.com/recipes/410698/ und beschlossen, zu versuchen, indem es diese. Es funktioniert ohne das nun zurück.
BEARBEITEN wieder: Geändert, um es ein paar Sekunden schneller.
Edit 3; geändert-Funktion statt Klasse
getestet:
Ausgabe:
Mit settrace verlangsamt es sehr stark.
Durch die Zeit, die der Dekorator ruft die Funktion Objekt
f
, es ist schon zusammengestellt-speziell, es ist schon zusammengestellt mit dem wissen, dassx
lokal ist (weil es zugeordnet ist, mit der+=
Zuordnung), die normale Optimierung (in2.*
können Sie besiegen die-Optimierung, bei der eine Staffelung Preis Leistung, indem Sief
mitexec ''
; in2.*
können Sie nicht besiegen-Optimierung). Im wesentlichen verwenden die syntax, die Sie sich sehnen, müssen Sie neu kompilierenf
(durch die Wiederherstellung seiner Quellen, wenn Sie wissen, Sie werden zur Laufzeit verfügbar, oder viel schwieriger, durch bytecode-hacks) mit irgendwie-modifizierten Quellen -- sobald Sie sich entschieden haben, diesen Weg zu gehen, ist der einfachste Ansatz ist wohl zu ändernx
inf.x
ganzen Körper vonf
.Persönlich, wenn ich finde mich kämpft so hart gegen die Sprache (oder andere Technologie), dass ich versuche, meinem Willen beugen zu verhängen, meine Wünsche, die ich bestätigen, dass ich entweder mit der falschen Sprache (oder einer anderen Technologie), wenn diese Wünsche sind absolut entscheidend, und dann die Lösung muß die Technologie ändern; oder, wenn diese Wünsche sind nicht entscheidend, Sie aufzugeben.
So oder so, ich gebe den Versuch auf, verzerren die Sprache zu weit Weg von den offensichtlichen design-Absichten: auch wenn ich mir einige hacky, fragile Unordnung, es würde kein Zweifel sein, wartbaren. In diesem Fall Python ' s Wunsch Absichten sind sehr klar: barenames, dass ein re-bound innerhalb von Funktionen sind einheimische, die Funktion, es sei denn, die ausdrücklich als globals -- Zeitraum. So, Ihr Versuch zu machen, barenames (, die wieder gebunden wird, innerhalb einer Funktion) etwas völlig anderes bedeuten als "einheimische" ist genau diese Art von kämpfen.
Bearbeiten: Wenn Sie bereit sind zu geben, bis auf das beharren auf die Verwendung barenames für Ihre "Statik", dann plötzlich " Sie kämpfen nicht gegen Python mehr, sondern Sie "gehen mit dem Korn," der Sprache (trotz der design-glitch von
global
[undnonlocal
], aber das ist ein separates schimpfen;-). So zum Beispiel:Diese funktioniert genau so, wie Sie es wünschen, drucken 1 und dann 2. (Ich bin mit
__builtin__
machen es einfach zu bedienen istwith_static
zu schmücken Funktionen, die das Leben in jedem Modul auch immer, natürlich). Könnten Sie haben verschiedene Implementierungen, aber der entscheidende Punkt einer gute Implementierung ist, dass "statische Variablen" werden qualifizierte Namen, nicht barenames -- machen Sie ausdrücklich, dass Sie keine lokalen Variablen, das Spiel mit der Maserung der Sprache, und so weiter. (Ähnlich built-in Container und qualifizierten Namen, die auf Ihnen basieren, sollte verwendet wurden, in der Python-design, anstelle derglobal
undnonlocal
design-Pannen, um anzugeben, andere Arten von Variablen, die nicht lokal sind, und sollten daher nicht verwendet werden barenames... ah gut, Sie selbst zu implementieren, eineglobvar
spezielle container auf den gleichen Linien von den obenstatic
lieben, ohne selbst benötigen, Dekoration, obwohl, ich bin mir nicht so sicher, das ist durchaus machbar für dienonlocal
Fall [vielleicht mit einige Dekoration und die kleinste Menge, von der schwarzen Magie...;=)]).Bearbeiten: Kommentare weist darauf hin, dass der code wie angegeben funktioniert nicht, wenn Sie nur schmücken den eine Funktion zurückgibt, die einen Verschluss (statt zu schmücken, die Schließung selbst). Das ist richtig: natürlich müssen Sie schmücken die spezifische Funktion, die verwendet das
static
(und es kann nur eine definition von Funktion-static
Variablen!), keine random-Funktion, die nicht in der Tat nutzen diestatic
sondern eben gerade in einige lexikalische Verbindung mit dem hat. Zum Beispiel:dieser Werke, während Sie die Dekorator
f
stattg
nicht (und gar nicht).Wenn die tatsächlichen desiderate sind nicht über statische Variablen (sichtbar und nutzbar nur innerhalb einer Funktion), aber einige hybrid-Ding, brauchbar, in einer bestimmten eigenartigen Bündel von Funktionen, die angegeben werden muss sehr exakt (und ohne Zweifel sehr unterschiedlich ausgeführt, je nachdem, was die tatsächlichen Spezifikationen sind) - und im Idealfall das muss geschehen in einem neuen und trennen SO Fragen, da diese (die ist speziell über statische statt), und die eine Antwort auf diese konkrete Frage, schon reichlich groß genug.
nonlocal
ist nur eine weitere Variante desglobal
(ich weiß nicht wie, ich denke, Sie sitzen quer die meisten Python 's ansonsten ziemlich konsistente design, und mit einem speziellen Schlüsselwort an, aus denen qualifizierte Namen wäre viel besser gewesen-aber klar ich verloren, dass die Debatte in Bezug auf Guido' s endgültige Entscheidungen). Ich kann mein edit beantworten, um zu zeigen, wie das funktionieren würde.f
gibt einen Verschluss.Hier ist eine wirklich einfache Lösung, die funktioniert genauso wie normale python-statische Variablen.
Beispiel:
Diese genauer entspricht die normale Art und Weise python statische Variablen
Könnte man so etwas machen (aber das habe ich noch nicht getestet, ausgiebig; verwendet CPython 2.6):
Es erfordert Deklaration von Variablen, Globale und Schatten top-level-globalen Variablen, aber sonst funktionieren sollte. Nicht sicher über die Leistung, obwohl.
Wie über diese, ohne Dekoratoren?
Und hier ist es in Aktion:
Hier ist etwas, das vielleicht viel klarer. Es sich nicht um irgendwelche Dekorateure oder hacking.
Nun haben Sie Ihre Funktion
f
mit einer statischen variable.self.x
oder irgendetwas anderes, das ist nicht ein barename).Wenn Sie brauchen, um zu speichern Zustand zwischen den aufrufen einer Funktion, Sie sind fast immer besser dran mit einem generator/coroutine oder ein Objekt. Da möchte man die Verwendung von "nackten" Namen der Variablen, dann werden Sie wollen die koroutine version.
Das Ergebnis ist eine Funktion, die sich die Gesamtwerte der drei Werte übergeben, genau so, wie wenn es hatte, statische Variablen, aber die Akkus sind plain old lokale Variablen in dem, was ist im wesentlichen eine unendliche generator.
return
- Anweisung in einer Funktion, die sogar dann. Wenn ich einige Zeit, obwohl, es scheint so, als wäre es ein Spaß-Projekt.Einem leichten zwicken ein weiterer anwser:
Fand ich es eklig zum überschreiben eines builtin-name, der eine Funktion argument-name, also habe ich
**dict
in die mehr kanonische**kwargs
. Ich auch rettete ein paar Zeilen und IMO aus der code sauberer durch den Bau einer neuen dict mitdict(the_original, **the_updates)
. Schließlich rettete ich ein paar Zeilen durch Aufruf der Konstruktor-Funktion übertype(func)
eher als ein import - ---type und class-Objekte sind factory-Methoden, also nutze Sie!Ich auch entfernt eine
global
Erklärung. Dies funktioniert so lange, wie Sie nicht erneut binden der Variablen, d.h. das entfernenglobal
macht in der Tat die Zeiger (aber nicht das Objekt) nur-lese -. Wenn Sie es auf diese Weise, vielleichtlet
ist ein besserer name alsstatic
für die Bindung so eingeführt.x += 1 UnboundLocalError: local variable 'x' referenced before assignment
.global
Erklärung funktioniert, solange die variable ist schreibgeschützt, die deinem Beispiel verstößt. Es könnte funktionieren, wenn x ein iadd - Methode, aber.