依靠__del __()在Python中进行清理是否不可靠?


问题内容

我在阅读不同的方式来清理对象在Python中,我已经对这些问题(跌跌撞撞12)基本上说,清理使用__del__()是不可靠的,下面的代码应该避免:

def __init__(self):
    rc.open()

def __del__(self):
    rc.close()

问题是,我恰好使用了这段代码,并且无法重现以上问题中引用的任何问题。就我所知,我无法使用带with语句的替代方法,因为我为封闭源代码软件(testIDEA,有人吗?)提供了一个Python模块。该软件将创建特定类的实例并进行处理,这些实例必须准备好在两者之间提供服务。__del__()我看到的唯一替代方法是手动调用,open()close()根据需要进行调用,我认为这将很容易发生错误。

我了解到,当我关闭解释器时,无法保证我的对象将被正确销毁(并且不会打扰我,哎呀,甚至Python作者都认为还可以)。
除此之外,我是否通过__del__()清理来玩火?


问题答案:

您会观察到垃圾回收语言中的终结器的典型问题。Java拥有它,C#拥有它,并且它们都提供了基于范围的清理方法,例如Pythonwith关键字来处理它。

主要问题是,垃圾收集器负责清理和销毁对象。在C
++中,对象超出范围时将被销毁,因此您可以使用RAII并具有明确定义的语义。在Python中,只要GC喜欢,对象就会超出范围并继续存在。根据您的Python实现,这可能有所不同。CPython及其基于引用计数的GC相当不错(因此您很少看到问题),而PyPy,IronPython和Jython可能会使对象存活很长时间。

例如:

def bad_code(filename):
    return open(filename, 'r').read()

for i in xrange(10000):
    bad_code('some_file.txt')

bad_code泄漏文件句柄。在CPython中没关系。引用计数降至零,并立即删除。在PyPy或IronPython中,由于耗尽所有可用的文件描述符(ulimit在Unix或Windows上最多为509句柄),您可能会遇到IOError或类似问题。

使用上下文管理器进行基于范围的清理,with如果您需要保证清理,则它是首选。您确切地知道何时完成对象。但是有时您无法轻松实施这种范围的清理。那是当你可能会使用__del__atexit或类似的结构做在清理尽力而为。它不可靠,但总比没有好。

您可以给用户增加显式清理负担,也可以强制执行显式作用域,或者您可以随便赌博,__del__然后时不时地看到一些奇怪的地方(尤其是解释器关闭)。