Подтвердить что ты не робот

Python - Как написать декоратор, который восстанавливает cwd?

Как написать декоратор, который восстанавливает текущий рабочий каталог до того, что было до вызова декорированной функции? Другими словами, если я использую декоратор на функции, которая выполняет os.chdir(), cwd не будет изменяться после вызова функции.

4b9b3361

Ответ 1

Модуль path.py (который вы действительно должны использовать при работе с путями в скриптах python) имеет менеджер контекста:

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

#not anymore

(кредиты передаются этот пост в блоге от Роберто Алсины)

Ответ 2

Был дан ответ для декоратора; он работает на этапе определения функции по запросу.

С Python 2.5+ у вас также есть возможность сделать это на этапе вызова функции с помощью диспетчера контекстов:

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)

который можно использовать, если необходимо, во время вызова функции как:

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

Это хороший вариант.

EDIT: я добавил обработку ошибок, как это было предложено в кодепе. Поскольку мой ответ был проголосован, он справедлив, чтобы предложить полный ответ, все остальные вопросы в стороне.

Ответ 3

В данных ответах не учитывается, что обернутая функция может вызвать исключение. В этом случае каталог никогда не будет восстановлен. В приведенном ниже коде добавлена ​​обработка исключений для предыдущих ответов.

в качестве декоратора:

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

и как менеджер контекста:

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

Ответ 4

def preserve_cwd(function):
   def decorator(*args, **kwargs):
      cwd = os.getcwd()
      result = function(*args, **kwargs)
      os.chdir(cwd)
      return result
   return decorator

Вот как он используется:

@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