patron - qué es un decorador en python
Python: ¿cómo escribo un decorador que restaura el cwd? (4)
¿Cómo escribo un decorador que restaura el directorio de trabajo actual a lo que era antes de llamar a la función decorada? En otras palabras, si uso el decorador en una función que hace un os.chdir (), el cwd no se cambiará después de que se llame a la función.
def preserve_cwd(function):
def decorator(*args, **kwargs):
cwd = os.getcwd()
result = function(*args, **kwargs)
os.chdir(cwd)
return result
return decorator
Así es como se usa:
@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
La respuesta para un decorador ha sido dada; funciona en la etapa de definición de la función según lo solicitado.
Con Python 2.5+, también tiene una opción para hacer eso en la etapa de llamada de función usando un administrador de contexto:
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)
que se puede usar si es necesario en el tiempo de llamada de la función como:
print "getcwd before:", os.getcwd()
with remember_cwd():
walk_around_the_filesystem()
print "getcwd after:", os.getcwd()
Es una buena opción para tener.
EDITAR: Agregué el manejo de errores como lo sugiere codeape. Dado que mi respuesta ha sido votado, es justo ofrecer una respuesta completa, dejando de lado todas las demás cuestiones.
Las respuestas dadas no tienen en cuenta que la función envuelta puede generar una excepción. En ese caso, el directorio nunca será restaurado. El siguiente código agrega manejo de excepciones a las respuestas anteriores.
como decorador:
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
y como administrador de contexto:
@contextlib.contextmanager
def remember_cwd():
curdir = os.getcwd()
try:
yield
finally:
os.chdir(curdir)
El módulo path.py (que realmente debe usar si se trata de rutas en scripts de Python) tiene un administrador de contexto:
subdir = d / ''subdir'' #subdir is a path object, in the path.py module
with subdir:
# here current dir is subdir
#not anymore
(los créditos van a esta publicación del blog de Roberto Alsina)