Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在类中包装不安全的python方法(例如os.chdir)如何使其线程/异常安全?_Python_Exception Handling - Fatal编程技术网

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

在类中包装不安全的python方法(例如os.chdir)如何使其线程/异常安全?,python,exception-handling,Python,Exception Handling,在这个问题中,公认的答案建议将os.chdir调用包装在一个类中,以确保返回到原始dir异常的安全性。以下是建议的代码: class Chdir: def __init__( self, newPath ): self.savedPath = os.getcwd() os.chdir(newPath) def __del__( self ): os.chdir( self.savedPath ) 有人能详细说明一下如何使不安全的调用异常安

在这个问题中,公认的答案建议将os.chdir调用包装在一个类中,以确保返回到原始dir异常的安全性。以下是建议的代码:

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

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

有人能详细说明一下如何使不安全的调用异常安全吗?

\uu del\uu
在实例即将销毁时调用。因此,当您实例化此类时,当前工作目录将保存到实例属性中,然后调用os.chdir。当实例被销毁时(无论出于何种原因),当前目录将更改为其旧值

这在我看来有点不正确。据我所知,您必须在覆盖的
\uuuu del\uuu
中调用父级的
\uu del\uuu
,因此它应该更像这样:

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执行同样的操作吗?

此代码本身既不是线程安全的,也不是异常安全的。实际上,我不太确定你说的异常安全是什么意思。我想到了以下代码:

try:
    # something thrilling
except:
    pass

这是个糟糕的主意。例外情况并不是为了防范。写得好的代码应该是有用的。对这个问题的直接回答是:没有,发布的代码很糟糕

类似于以下的内容可以合理地使其“异常安全”(但更好的做法是避免chdir,而是使用完整路径):


这种精确的行为也可以写入到上下文管理器中

线程安全和异常安全实际上根本不是一回事。在这样的类中包装
os.chdir
调用是为了使其异常安全而不是线程安全

异常安全是你经常听到C++开发者谈论的话题。Python社区几乎没有这么多人谈论它。从Boost的文档中:

非正式地说,异常安全是指 组件意味着它显示 例外情况下的合理行为 在执行过程中抛出。对于 大多数人认为“合理”一词 包括所有通常的期望 对于错误处理:这需要资源 不应该泄露,而且 程序应保留在 定义良好的状态,以便执行 我们可以继续

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

这种使用仅为清理而存在的对象的模式是“”或“RAII”的一种形式。这种技术在C++中非常流行,但由于Python的原因,在以下方面不受欢迎:

  • Python有
    try
    finally
    ,它的作用几乎相同,是Python中更常见的习惯用法
  • Python中的析构函数(
    \uu del\uu
    )在某些实现中是不可靠/不可预测的,因此以这种方式使用它们有些不受鼓励。在cpython中,只要不涉及周期(即:通过引用计数处理删除),它们就非常可靠和可预测,但在其他实现中(Jython和我相信IronPython),当垃圾收集器处理它时,删除就会发生,这可能要晚得多。(有趣的是,这并不能阻止大多数Python程序员依靠
    \uu del\uu
    关闭打开的文件。)
  • 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)

我认为“异常安全”的意思是:“即使由于引发异常而失去控制,我们也保证返回到原始目录”。有趣的是,你说它不是异常安全的,然后承认你不知道异常安全是什么意思。不管异常安全是什么意思;你能说“仅此代码是异常安全的”吗?我指的是问题中的Chdir类。Shylent-没错。这就是我通过“异常安全”得到的意思。最好使用with语句(Python 2.5+)
os.chdir(newPath)
可能不应该出现在
try
语句中-如果失败,当前工作目录没有更改,因此不需要重置它。(在这种情况下,它是无害的,因为
os.chdir(os.getcwd())
是一个no-op,但是如果
saved\u path
是相对的,这将是一个问题)
saved_path = os.getcwd()
os.chdir(new_path)
try:
    # code that does stuff in new_path goes here
finally:
    os.chdir(saved_path)