3

python 文档__del__解释了当对象的__del__引用计数减少到零时可以调用对象的方法。它总是立即调用(即同步)吗?或者该__del__方法是否有可能“在未来的某个时候”被调用?

此外,这个问题的答案是否普遍适用于 Python?或者是否授予语言实现一些自由度?(我使用 CPython。)

对于这个问题,假设如下:

  • 有问题的对象继承自object.
  • 有问题的对象具有自定义__del__实现。
  • 对象的自定义__del__实现不会创建对任何对象的新引用。
  • 有问题的对象不是引用循环的一部分。
  • 解释器未处于关闭过程中。

据我所知,围绕这个话题似乎有很多困惑。为了避免一些不必要的讨论,让我举一些不可接受的答案的例子:

  • “不要用__del__!很混乱!”
  • “不要使用__del__!它不是'pythonic'。”
  • “不要使用__del__,而是使用上下文管理器。”
  • 在没有引用可靠来源的情况下断言什么是或不保证的任何答案。(请随意引用其他 SO 答案,但不要依赖它们作为您的唯一来源。在这种情况下,“可信”是指文档中的某些内容,或有信誉的人,甚至可能是 CPython 来源本身。)

用一个例子来解释这个问题,考虑这个代码:

class C(object):
    def __init__(self, i):
        self.i = i

    def __del__(self):
        print "C.__del__:", self.i

print "Creating list"
l = [C(0), C(1), C(2)]

print "Popping item 1"
l.pop(1)

print "Clearing list"
l = []

print "Exiting..."

产生以下输出:

$ python test_del.py
Creating list
Popping item 1
C.__del__: 1
Clearing list
C.__del__: 2
C.__del__: 0
Exiting...

请注意,在此示例中,__del__ 同步调用的。这种行为是由语言保证的吗?(请记住上面列出的假设。)

4

2 回答 2

3

来自 Python 语言参考(Python 2.7.3 版),第 3 章,数据模型

对象永远不会被显式销毁;但是,当它们变得无法访问时,它们可能会被垃圾收集。允许实现推迟垃圾收集或完全忽略它——只要没有收集仍然可访问的对象,垃圾收集的实现方式就是实现质量的问题。

CPython 实现细节: CPython 目前使用引用计数方案,对循环链接的垃圾进行(可选)延迟检测,一旦它们变得不可访问,它就会收集大多数对象,但不能保证收集包含循环引用的垃圾。gc有关控制循环垃圾收集的信息,请参阅模块的文档。其他实现的行为不同,CPython 可能会改变。当对象变得无法访问时,不要依赖于立即完成对象(例如:始终关闭文件)。

于 2012-12-03T19:30:54.473 回答
1

语言不保证该行为。例如,请参阅PyPy 关于其垃圾收集方案的文档,其中明确指出__del__在 PyPy 中调用的时间与 CPython 不同。

如果您的对象不是引用循环的一部分,那么我知道这种行为在 CPython 中是可靠的,但我不知道有任何明确的保证。

于 2012-12-03T19:31:20.247 回答