Python 如何编写恢复cwd的装饰程序?

Python 如何编写恢复cwd的装饰程序?,python,decorator,cwd,Python,Decorator,Cwd,如何编写一个装饰程序,将当前工作目录恢复到调用装饰函数之前的状态?换句话说,如果我在执行os.chdir()的函数上使用decorator,则调用该函数后,cwd不会更改 def preserve_cwd(function): def decorator(*args, **kwargs): cwd = os.getcwd() result = function(*args, **kwargs) os.chdir(cwd) return res

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

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

一个装饰师的答案已经给出;它在函数定义阶段按要求工作

对于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)
@contextlib.contextmanager
def remember_cwd():
    curdir = os.getcwd()
    try:
        yield
    finally:
        os.chdir(curdir)
subdir = d / 'subdir' #subdir is a path object, in the path.py module
with subdir:
  # here current dir is subdir

#not anymore
这是一个很好的选择


编辑:我按照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
作为上下文管理器:

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)
@contextlib.contextmanager
def remember_cwd():
    curdir = os.getcwd()
    try:
        yield
    finally:
        os.chdir(curdir)
subdir = d / 'subdir' #subdir is a path object, in the path.py module
with subdir:
  # here current dir is subdir

#not anymore
该模块(如果在python脚本中处理路径,您确实应该使用该模块)有一个上下文管理器:

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)
@contextlib.contextmanager
def remember_cwd():
    curdir = os.getcwd()
    try:
        yield
    finally:
        os.chdir(curdir)
subdir = d / 'subdir' #subdir is a path object, in the path.py module
with subdir:
  # here current dir is subdir

#not anymore

(罗伯托·阿尔西纳的学分)

你问了这个问题并在3分钟内自己回答了,因为…?很明显,你甚至在问问题之前就已经有了答案(这几乎无法改进)。我真的很想知道你的理由。FAQ上说“问和回答你自己的编程问题也很好”。它列出了三个必要的问题标准,“你不知道答案”不是其中之一。我已经编写了代码,但后来(重构后)发现我不需要它。我认为stackoverflow是一个很好的归档场所,也许其他人也能从中受益。我认为“Jeopardy”的评论应该是指标题仍然应该是“如何为X编写装饰器?”,而不是“这是一个有用的X装饰器”。我同意问题中的一个注释可以避免人们在你打字时浪费时间在重复的解决方案上。但它们可能比你的更好…我很高兴我问了这个问题,因为codeape改进了我的答案,并且TthiΖΖΖΖΖΖΥ提出了一个我没有想到的上下文管理器。它可以用来编写前面提到的decorator:)错误处理是否需要显式尝试/最终?我认为上下文管理器的重点是管理器。总是调用“退出”。但是,我从未尝试过contextlib中的decorator,因此我不知道问题出在哪里。不,它不需要显式的
try/finally
,但您很可能需要
try/except
子句来处理失败。如果path.py现在是内置的,也许您应该回答。不幸的是,它不是,但是谢谢,我没有意识到这个问题,我想我误解了你的答案。您的意思是上下文管理器内置于path.py中吗?(我以为你的意思是path.py现在内置在Python中。)因为Daryl Spitzer假设
path.py
pathlib
相同,你也可以假设它们的上下文管理器的行为方式相同,但它们不是:
pathlib.path
不接触CWD,而是充当
open()
(“关闭”)中的上下文管理器可能打开的文件描述符)。