2009-11-10 27 views
4

在问题How do I "cd" in python中,接受的答案建议在类中包装os.chdir调用,以便返回到原始目录异常安全。这里是推荐的代码:如何在类中包装不安全的python方法(例如os.chdir)使其线程/异常安全?

class Chdir:   
    def __init__(self, newPath): 
    self.savedPath = os.getcwd() 
    os.chdir(newPath) 

    def __del__(self): 
    os.chdir(self.savedPath) 

有人可以详细说明这是如何工作,使不安全的调用异常安全吗?

回答

7

线程安全性和异常安全性根本不是一回事。在这样的班级中召唤os.chdir呼叫是为了使其异常安全不是线程安全的

异常安全是您经常会听到的C++开发人员所讨论的内容。它在Python社区中几乎没有被讨论过。从Boost的Exception-Safety in Generic Components文件:

通俗地说,在 成分异常安全意味着它具有 合理行为异常时 在执行过程中被抛出。对于 大多数人来说,“合理”一词 包含了所有的错误处理通常预期 :资源 不应该被泄露,那 程序应保持在 定义良好的状态,以便执行 可以继续。

因此,您提供的代码片段中的想法是为了确保在发生异常的情况下,程序将返回到定义明确的状态。在这种情况下,进程将返回到它所启动的目录中,无论os.chdir本身是否失败,或者导致抛出异常并删除“Chdir”实例。

这种使用仅用于清理的对象的模式是“Resource Acquisition Is Initialization”或“RAII”的一种形式。该技术是在C++中很流行,但在Python中并不是如此受欢迎的几个原因:

  • Python有try ...... finally,供应几乎相同的目的,是在Python更常见的成语。
  • Python中的析构函数(__del__)在某些实现中不可靠/不可预知,因此以某种方式使用它们有点令人沮丧。在cpython中,只要不涉及循环(即:当删除由引用计数处理),但在其他实现中(Jython和我相信IronPython)删除发生在垃圾收集器周围时,它们恰好是非常可靠且可预测的它可能会晚得多。 (有趣的是,这并不妨碍大多数Python程序员依靠__del__来关闭它们的打开文件。)
  • Python有垃圾回收,所以你不需要像在C++中那样小心地进行清理。 (我不是说你不必须要小心可言,只是在普通情况下,你可以依靠GC做正确的事你。)

更“Python化”的方式写上面的代码将是:

saved_path = os.getcwd() 
os.chdir(new_path) 
try: 
    # code that does stuff in new_path goes here 
finally: 
    os.chdir(saved_path) 
+0

感谢劳伦斯。非常彻底和清晰。 – zlovelady 2009-11-10 18:38:47

+0

使用with语句更好(Python 2.5+) – compie 2011-08-17 15:05:18

1

__del__当实例即将销毁时调用。所以当你实例化这个类时,当前工作目录被保存到一个实例属性中,然后调用os.chdir。当实例被销毁时(无论出于何种原因),当前目录被更改为旧值。

这看起来有点不正确。据我所知,你必须电话父母__del__在你重写__del__,所以应该更多这样的:

class Chdir(object):   
    def __init__(self, new_path): 
    self.saved_path = os.getcwd() 
    os.chdir(new_path) 

    def __del__(self): 
    os.chdir(self.saved_path) 
    super(Chdir, self).__del__() 

也就是说,除非我失去了一些东西,当然。

(顺便说一句,你能不能做到使用contextmanager一样吗?)

-2

仅此代码是线程安全的,也没有异常安全。其实我并不确定你的意思是异常安全。下面的代码想到:

try: 
    # something thrilling 
except: 
    pass 

这是一个可怕的想法。例外不是防范。写得好的代码应该是catch exceptions,并对它们做一些有用的事情。

+1

我认为“异常安全”,他的意思如下:“即使失去控制因异常被提出,我们都保证恢复到原来的目录” 。 – shylent 2009-11-10 17:49:32

+0

有趣的是,你说它不是例外的安全,然后承认你不知道什么是异常安全的手段。 – 2009-11-10 18:01:01

+0

无论什么异常安全的手段;你能说“单独的代码是异常安全的吗?”?通过代码我的意思是在问题中的Chdir类。 – muhuk 2009-11-10 18:21:48

5

问题的直接答案是:它没有,发布的代码是可怕的。

像下面可能是合理的,使之“异常安全”(但更好的是要避免的chdir和使用完整路径来代替):

saved_path = os.getcwd() 
    try: 
    os.chdir(newPath) 
    do_work() 
    finally: 
    os.chdir(saved_path) 

而这个精确的行为也可以写进情境管理器。

+0

'os.chdir(newPath)'可能不应该放在'try'语句中 - 如果失败,当前工作目录没有改变,所以不需要重置它。 (在这种情况下,它是无害的,因为'os.chdir(os.getcwd())'是一个无操作,但如果'saved_pa​​th'是相对的,这将是麻烦) – Thomas 2014-08-12 04:26:06