Pergunta

Como escrevo um decorador que restaura o diretório de trabalho atual ao que era antes que a função decorada fosse chamada? Em outras palavras, se eu usar o decorador em uma função que faz um os.chdir(), a CWD não será alterada depois que a função for chamada.

Foi útil?

Solução

o path.py O módulo (que você realmente deve usar se lidar com caminhos em scripts Python) tem um gerente de contexto:

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

#not anymore

(os créditos vão para esta postagem do blog de Roberto Alsina)

Outras dicas

A resposta para um decorador foi dada; Funciona no estágio de definição da função, conforme solicitado.

Com o Python 2.5+, você também tem a opção de fazer isso na função ligar estágio usando um gerenciador 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 pode ser usado, se necessário, no tempo de chamada da função como:

print "getcwd before:", os.getcwd()
with remember_cwd():
    walk_around_the_filesystem()
print "getcwd after:", os.getcwd()

É uma boa opção ter.

EDIT: Adicionei o manuseio de erros, conforme sugerido pelo Codeape. Como minha resposta foi elevada, é justo oferecer uma resposta completa, todos os outros problemas de lado.

As respostas dadas não levam em consideração que a função embrulhada pode aumentar uma exceção. Nesse caso, o diretório nunca será restaurado. O código abaixo adiciona manipulação de exceções às respostas 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

E como gerente de contexto:

@contextlib.contextmanager
def remember_cwd():
    curdir = os.getcwd()
    try:
        yield
    finally:
        os.chdir(curdir)
def preserve_cwd(function):
   def decorator(*args, **kwargs):
      cwd = os.getcwd()
      result = function(*args, **kwargs)
      os.chdir(cwd)
      return result
   return decorator

Veja como é usado:

@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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top