How do I write a decorator that restores the current working directory to what it was before the decorated function was called? In other words, if I use the decorator on a function that does an os.chdir()
, the cwd will not be changed after the function is called.
如何编写一个装饰器,将当前工作目录恢复到调用修饰函数之前的状态?换句话说,如果我在执行os.chdir()的函数上使用装饰器,则在调用函数后不会更改cwd。
4 个解决方案
#1
16
The path.py module (which you really should use if dealing with paths in python scripts) has a context manager:
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
(credits goes to this blog post from Roberto Alsina)
(来自Roberto Alsina的博客文章)
#2
34
The answer for a decorator has been given; it works at the function definition stage as requested.
给出了装饰者的答案;它根据请求在函数定义阶段工作。
With Python 2.5+, you also have an option to do that at the function call stage using a context manager:
使用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)
which can be used if needed at the function call time as:
如果在函数调用时需要,可以使用它:
print "getcwd before:", os.getcwd()
with remember_cwd():
walk_around_the_filesystem()
print "getcwd after:", os.getcwd()
It's a nice option to have.
这是一个不错的选择。
EDIT: I added error handling as suggested by codeape. Since my answer has been voted up, it's fair to offer a complete answer, all other issues aside.
编辑:我添加了codeape建议的错误处理。由于我的答案已被投票,所以提供完整的答案,除了所有其他问题是公平的。
#3
18
The given answers fail to take into account that the wrapped function may raise an exception. In that case, the directory will never be restored. The code below adds exception handling to the previous answers.
给定的答案未考虑包装函数可能引发异常。在这种情况下,永远不会恢复该目录。下面的代码为以前的答案添加了异常处理。
as a decorator:
作为装饰者:
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
and as a context manager:
并作为上下文管理器:
@contextlib.contextmanager
def remember_cwd():
curdir = os.getcwd()
try:
yield
finally:
os.chdir(curdir)
#4
3
def preserve_cwd(function):
def decorator(*args, **kwargs):
cwd = os.getcwd()
result = function(*args, **kwargs)
os.chdir(cwd)
return result
return decorator
Here's how it's used:
以下是它的使用方法:
@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
#1
16
The path.py module (which you really should use if dealing with paths in python scripts) has a context manager:
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
(credits goes to this blog post from Roberto Alsina)
(来自Roberto Alsina的博客文章)
#2
34
The answer for a decorator has been given; it works at the function definition stage as requested.
给出了装饰者的答案;它根据请求在函数定义阶段工作。
With Python 2.5+, you also have an option to do that at the function call stage using a context manager:
使用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)
which can be used if needed at the function call time as:
如果在函数调用时需要,可以使用它:
print "getcwd before:", os.getcwd()
with remember_cwd():
walk_around_the_filesystem()
print "getcwd after:", os.getcwd()
It's a nice option to have.
这是一个不错的选择。
EDIT: I added error handling as suggested by codeape. Since my answer has been voted up, it's fair to offer a complete answer, all other issues aside.
编辑:我添加了codeape建议的错误处理。由于我的答案已被投票,所以提供完整的答案,除了所有其他问题是公平的。
#3
18
The given answers fail to take into account that the wrapped function may raise an exception. In that case, the directory will never be restored. The code below adds exception handling to the previous answers.
给定的答案未考虑包装函数可能引发异常。在这种情况下,永远不会恢复该目录。下面的代码为以前的答案添加了异常处理。
as a decorator:
作为装饰者:
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
and as a context manager:
并作为上下文管理器:
@contextlib.contextmanager
def remember_cwd():
curdir = os.getcwd()
try:
yield
finally:
os.chdir(curdir)
#4
3
def preserve_cwd(function):
def decorator(*args, **kwargs):
cwd = os.getcwd()
result = function(*args, **kwargs)
os.chdir(cwd)
return result
return decorator
Here's how it's used:
以下是它的使用方法:
@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