2008-10-03 11 views
23

¿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.Python - ¿Cómo escribo un decorador que restaura el cwd?

+1

Y usted hizo la pregunta y la respondió usted mismo en 3 minutos porque ...? Obviamente tuviste la respuesta (que difícilmente se puede mejorar) incluso antes de hacer la pregunta. Realmente me gustaría saber tu razonamiento. – tzot

+6

Preguntas frecuentes dice "También es perfectamente correcto preguntar y responder a su propia pregunta de programación". Enumera tres criterios requeridos para las preguntas, y "usted no sabe la respuesta" no es uno de ellos. –

+2

Escribí el código y luego resultó (después de la refactorización) que no lo necesitaba. Pensé que stackoverflow es un buen lugar para archivarlo, y quizás otros puedan beneficiarse. –

Respuesta

13

El módulo path.py (que realmente debería usar si se trata de caminos en los scripts de Python) tiene un gestor de contexto:

subdir = d/'subdir' #subdir is a path object, in the path.py module 
with subdir: 
    # here current dir is subdir 

#not anymore 

(créditos van a this blog post de Rob erto Alsina)

+1

Si path.py ahora está incorporado, quizás debería responder http://stackoverflow.com/questions/3899761/will-the-real-path-py-please-stand-up. –

+0

desafortunadamente no lo es, pero gracias. No estaba al tanto de la pregunta – CharlesB

+0

. Creo que malinterpreté su respuesta. ¿Quiso decir que el administrador de contexto está integrado en path.py? (Pensé que querías decir que path.py ahora está integrado en Python.) –

3
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 
+2

Necesita manejo de errores, ver mi respuesta. – codeape

30

La respuesta para un decorador se le ha dado; 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 que en la función llamada etapa usando un gestor 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 utilizar si es necesario en el momento llamada a 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.

EDITAR: He añadido 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.

+0

* Y * se puede utilizar para escribir el decorador antes mencionado :) – Constantin

+1

Necesita manejo de errores, ver mi respuesta. – codeape

+0

¿El manejo de errores necesita un try/finally explícito? Pensé que el punto de los administradores de contexto era que siempre se llamaba MANAGER .__ exit__. Pero entonces, nunca he probado el decorador desde contextlib, así que no sé cuáles son los problemas. –

17

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 gestor de contexto:

@contextlib.contextmanager 
def remember_cwd(): 
    curdir = os.getcwd() 
    try: 
     yield 
    finally: 
     os.chdir(curdir) 
Cuestiones relacionadas