我一直在考虑如何用Python编写类。更具体地说,如何实现构造函数以及如何销毁对象。我不想依靠CPython的引用计数来进行对象清理。这基本上告诉我应该使用with语句来管理我的对象生命周期,并且我需要一个显式的close / dispose方法(如果对象也是一个上下文管理器,则可以从__exit__
调用此方法)。
class Foo(object):
def __init__(self):
pass
def close(self):
pass
现在,如果我的所有对象都以这种方式运行,并且我的所有代码都使用语句或显式调用close()
(或dispose()
),我真的不需要我放任何对象__del__
中的代码。我们真的应该使用__del__
处理我们的对象吗?
答案 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的解决方案。