如何在类中包装不安全的python方法(例如os.chdir)使其线程/异常安全?

zlo*_*ady 4 python exception-handling

如何在python中"cd"的问题中,接受的答案建议在类中包装os.chdir调用以使返回原始dir异常安全.这是推荐的代码:

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

  def __del__( self ):
    os.chdir( self.savedPath )
Run Code Online (Sandbox Code Playgroud)

有人可以详细说明这是如何使不安全的呼叫异常安全的吗?

Lau*_*ves 7

线程安全和异常安全根本不是一回事.os.chdir在这样的类中包装调用是尝试使其异常安全而不是线程安全.

异常安全是您经常听到的C++开发人员所谈论的内容.在Python社区中几乎没有谈到它.来自Boost的例外 - 通用组件安全文档:

非正式地,组件中的异常安全意味着它在执行期间抛出异常时表现出合理的行为.对于大多数人来说,术语"合理"包括错误处理的所有常规期望:不应泄漏资源,并且程序应保持在明确定义的状态,以便可以继续执行.

因此,您提供的代码段中的想法是确保在异常的情况下,程序将返回到定义良好的状态.在这种情况下,进程将在它开始的目录中返回,无论os.chdir本身是否失败,或者是什么原因导致抛出异常并删除"Chdir"实例.

使用仅用于清理的对象的这种模式是" 资源获取是初始化 "或"RAII"的形式.这种技术在C++中非常流行,但由于以下几个原因在Python中不太流行:

  • Python有try... finally,它的用途几乎相同,是Python中比较常见的习惯用语.
  • __del__Python中的Destructors()在某些实现中是不可靠/不可预测的,因此有点不鼓励使用它们.在cpython中,只要不涉及循环(即:当通过引用计数处理删除时),它们恰好是非常可靠和可预测的,但在其他实现中(Jython和我相信也是IronPython)当垃圾收集器到达时会发生删除它,可能会更晚.(有趣的是,这并不能阻止大多数Python程序员依赖于__del__关闭他们打开的文件.)
  • Python具有垃圾收集功能,因此您不必像在C++中那样谨慎地进行清理.(我并不是说你根本不必小心,只是在常见的情况下,你可以依靠gc为你做正确的事.)

编写上述代码的更"pythonic"方式是:

saved_path = os.getcwd()
os.chdir(new_path)
try:
    # code that does stuff in new_path goes here
finally:
    os.chdir(saved_path)
Run Code Online (Sandbox Code Playgroud)


u0b*_*6ae 5

这个问题的直接答案是:它没有,发布的代码很糟糕.

像下面这样的东西可能是合理的,使它"异常安全"(但更好的是避免chdir并使用完整路径):

  saved_path = os.getcwd()
  try:
    os.chdir(newPath)
    do_work()
  finally:
    os.chdir(saved_path)
Run Code Online (Sandbox Code Playgroud)

并且这种精确的行为也可以写入上下文管理器.