在__del__中关闭/处理对象真的可以吗?

时间:2009-07-10 19:26:49

标签: python

我一直在考虑如何用Python编写类。更具体地说,如何实现构造函数以及如何销毁对象。我不想依靠CPython的引用计数来进行对象清理。这基本上告诉我应该使用with语句来管理我的对象生命周期,并且我需要一个显式的close / dispose方法(如果对象也是一个上下文管理器,则可以从__exit__调用此方法)。

class Foo(object):
    def __init__(self):
        pass
    def close(self):
        pass

现在,如果我的所有对象都以这种方式运行,并且我的所有代码都使用语句或显式调用close()(或dispose()),我真的不需要我放任何对象__del__中的代码。我们真的应该使用__del__处理我们的对象吗?

3 个答案:

答案 0 :(得分:13)

简短回答:不。

答案很长:使用__del__很棘手,主要是因为它不能保证被调用。这意味着你不能做那些绝对必须做的事情。这反过来意味着__del__基本上只能用于迟早会发生的清理,比如清理流程退出时要清理的资源,所以{{1}无关紧要}没有被调用。当然,这些通常与Python将为您做的事情相同。所以这有点使__del__无用。

此外,当Python垃圾收集时调用__del__,并且您不想等待Pythons垃圾收集,这意味着无论如何都不能使用__del__

所以,不要使用__del__。请改用__del__

仅供参考:以下是非循环情况的示例,其中析构函数未被调用:

__enter__/__exit__

好的,所以这是一个类属性。显然这是一个特例。但它只是表明确保调用class A(object): def __init__(self): print('Constructing A') def __del__(self): print('Destructing A') class B(object): a = A() 并不简单。我很确定我已经看到了更多非循环的情况,其中__del__未被调用。

答案 1 :(得分:8)

不一定。有循环引用时会遇到问题。 Eli Bendersky在他的博客文章中做了很好的解释:

答案 2 :(得分:0)

如果您确定不会进入循环引用,那么以这种方式使用__del__就可以了:只要引用计数变为零,CPython VM就会调用该方法并销毁该对象。

如果您打算使用循环引用 - 请仔细考虑,并检查弱引用是否有帮助;在许多情况下,循环引用是设计糟糕的第一个症状。

如果您无法控制对象的使用方式,那么使用__del__可能不安全。

如果您打算使用JPython或IronPython,__del__根本不可靠,因为最终对象破坏将在垃圾收集时发生,而这是您无法控制的。

总之,在我看来,__del__通常是非常安全和良好的;然而,在许多情况下,退一步可能会更好,并尝试从不同的角度看待问题;充分利用try / except和with contexts可能是一个更加pythonic的解决方案。