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

StackOverflow https://stackoverflow.com/questions/169070

  •  05-07-2019
  •  | 
  •  

Вопрос

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

Это было полезно?

Решение

Модуль 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

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

Другие советы

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

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

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()

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

РЕДАКТИРОВАТЬ: я добавил обработку ошибок, как предложено codeape. Поскольку за мой ответ проголосовали, справедливо предложить полный ответ, за исключением всех других вопросов.

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

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

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)
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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top