如何编写一个恢复当前工作目录的装饰器?

43 投票
5 回答
20657 浏览
提问于 2025-04-11 09:24

我该怎么写一个装饰器,让它在调用被装饰的函数之前的工作目录恢复到之前的状态?换句话说,如果我在一个会改变当前工作目录的函数上使用这个装饰器,比如用到os.chdir(),那么在这个函数调用后,当前工作目录就不会被改变。

5 个回答

28

之前的回答没有考虑到被包装的函数可能会出现错误。如果出现错误,目录就永远不会恢复。下面的代码在之前的回答基础上增加了错误处理。

作为一个装饰器:

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

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

从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的建议添加了错误处理。因为我的回答得到了点赞,所以提供一个完整的答案是公平的,其他问题暂且不提。

36

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的这篇博客

撰写回答