33

如何编写一个装饰器,将当前工作目录恢复到调用装饰函数之前的状态?换句话说,如果我在执行 an 的函数上使用装饰器,os.chdir()则调用函数后 cwd 将不会更改。

4

4 回答 4

49

已经给出了装饰者的答案;它按要求在函数定义阶段工作。

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

这是一个不错的选择。

编辑:我按照codeape的建议添加了错误处理。由于我的答案已被投票通过,因此提供一个完整的答案是公平的,除了所有其他问题。

于 2008-10-03T22:19:30.590 回答
32

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

(学分来自 Roberto Alsina的这篇博文)

于 2012-12-24T09:38:59.057 回答
24

给定的答案没有考虑到包装函数可能引发异常。在这种情况下,该目录将永远不会被恢复。下面的代码在前面的答案中添加了异常处理。

作为装饰者:

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)
于 2008-10-04T11:29:33.803 回答
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
于 2008-10-03T22:06:46.590 回答