Wie schreibe ich einen Dekorator, der das aktuelle Arbeitsverzeichnis auf das wiederherstellt, was es war, bevor die dekorierte Funktion aufgerufen wurde? Mit anderen Worten, wenn ich den Decorator für eine Funktion verwende, die ein os.chdir() ausführt, wird das cwd nicht geändert, nachdem die Funktion aufgerufen wurde.Python - Wie schreibe ich einen Dekorateur, der die cwd wiederherstellt?
Antwort
Das path.py Modul verfügt über einen Kontext-Manager (die Sie wirklich mit Pfaden in Python-Skripte, wenn Umgang verwenden sollten):
subdir = d/'subdir' #subdir is a path object, in the path.py module
with subdir:
# here current dir is subdir
#not anymore
(Dank geht an this blog post von Rob erto Alsina)
Wenn path.py jetzt eingebaut ist, sollten Sie vielleicht http://stackoverflow.com/questions/3899761/will-the-real-path-py-please-stand-up beantworten. –
leider ist es nicht, aber danke ich war mir der Frage nicht bewusst – CharlesB
Ich denke, ich habe Ihre Antwort falsch interpretiert. Meintest du, dass der context manager in path.py integriert ist? (Ich dachte du meinst path.py ist jetzt in Python integriert.) –
def preserve_cwd(function):
def decorator(*args, **kwargs):
cwd = os.getcwd()
result = function(*args, **kwargs)
os.chdir(cwd)
return result
return decorator
Hier ist, wie es verwendet wird:
@preserve_cwd
def test():
print 'was:',os.getcwd()
os.chdir('/')
print 'now:',os.getcwd()
>>> print os.getcwd()
/Users/dspitzer
>>> test()
was: /Users/dspitzer
now:/
>>> print os.getcwd()
/Users/dspitzer
Benötigt Fehlerbehandlung, siehe meine Antwort. – codeape
Die Antwort für einen Dekorateur gegeben wurde; Es funktioniert bei der Definition der Funktion wie gewünscht.
Mit Python 2.5+, Sie haben auch eine Option, dass Anruf Bühne an der Funktion zu tun, um einen Kontext-Manager:
from __future__ import with_statement # needed for 2.5 ≤ Python < 2.6
import contextlib, os
@contextlib.contextmanager
def remember_cwd():
curdir= os.getcwd()
try: yield
finally: os.chdir(curdir)
, die verwendet werden können, wenn bei der Funktionsaufruf Zeit benötigt wie:
print "getcwd before:", os.getcwd()
with remember_cwd():
walk_around_the_filesystem()
print "getcwd after:", os.getcwd()
Es ist eine schöne Option zu haben.
EDIT: Ich fügte Fehlerbehandlung wie von Codeape vorgeschlagen hinzu. Da meine Antwort gewählt wurde, ist es fair, eine vollständige Antwort anzubieten, alle anderen Fragen beiseite.
* Und * es kann verwendet werden, um den oben genannten Dekorator zu schreiben :) – Constantin
Benötigt Fehlerbehandlung, siehe meine Antwort. – codeape
Benötigt die Fehlerbehandlung einen expliziten try/finally? Ich dachte, der Punkt der Kontextmanager war, dass MANAGER .__ exit__ immer aufgerufen wurde. Aber ich habe den Decorator nie aus Contextlib probiert, also weiß ich nicht, was die Probleme sind. –
Die angegebenen Antworten berücksichtigen nicht, dass die umbrochene Funktion eine Ausnahme auslösen kann. In diesem Fall wird das Verzeichnis niemals wiederhergestellt. Der folgende Code fügt die Ausnahmenbehandlung zu den vorherigen Antworten hinzu.
als Dekorateur:
def preserve_cwd(function):
@functools.wraps(function)
def decorator(*args, **kwargs):
cwd = os.getcwd()
try:
return function(*args, **kwargs)
finally:
os.chdir(cwd)
return decorator
und als Kontext-Manager:
@contextlib.contextmanager
def remember_cwd():
curdir = os.getcwd()
try:
yield
finally:
os.chdir(curdir)
Und du hast die Frage gestellt und selbst in 3 Minuten beantwortet, weil ...? Offensichtlich hatten Sie die Antwort (die kaum verbessert werden kann), noch bevor Sie die Frage stellten. Ich würde wirklich gerne deine Argumentation wissen. – tzot
FAQ sagt "Es ist auch völlig in Ordnung, Ihre eigene Programmierfrage zu stellen und zu beantworten". Es enthält drei erforderliche Kriterien für Fragen, und "Sie kennen die Antwort nicht" gehört nicht dazu. –
Ich hatte den Code geschrieben und dann stellte sich heraus (nach Refactoring), dass ich ihn nicht brauchte. Ich dachte, Stackoverflow ist ein guter Ort, um es zu archivieren, und vielleicht können andere davon profitieren. –