python是否总是同步调用_del__?

python是否总是同步调用_del__?,python,Python,的python文档解释了当对象的引用计数减少到零时,可以调用对象的\uu del\uu方法。是否总是立即(即同步)调用?或者,\uuu del\uu方法是否可能在“将来某个时候”被调用 此外,这个问题的答案一般适用于Python吗?或者对语言实现给予了一些自由度?(我使用CPython。) 对于这个问题,假设如下: 有问题的对象继承自对象 有问题的对象有一个自定义的\uuu del\uu实现 对象的自定义\uuu del\uu实现不会创建对任何对象的新引用 所讨论的对象不是参考循环的一部分 解

的python文档解释了当对象的引用计数减少到零时,可以调用对象的
\uu del\uu
方法。是否总是立即(即同步)调用?或者,
\uuu del\uu
方法是否可能在“将来某个时候”被调用

此外,这个问题的答案一般适用于Python吗?或者对语言实现给予了一些自由度?(我使用CPython。)

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

  • 有问题的对象继承自
    对象
  • 有问题的对象有一个自定义的
    \uuu del\uu
    实现
  • 对象的自定义
    \uuu del\uu
    实现不会创建对任何对象的新引用
  • 所讨论的对象不是参考循环的一部分
  • 解释器未处于关闭过程中
据我所知,围绕这个话题似乎有很多困惑。为了避开一些不必要的讨论,让我举一些不可接受的答案的例子:

  • “不要使用
    \uuuu del\uuuu
    !这很混乱!”
  • “不要使用
    \uu del\uu
    !它不是‘pythonic’。”
  • 不要使用
    \uuu del\uuu
    ,而是使用上下文管理器
  • 任何在没有可靠来源的情况下断言什么是或什么不是保证的答案。(请随意引用其他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\u del.py
创建列表
弹出项目1
C.uuu del_uuuuu:1
清算清单
C.uu del_uu:2
C.uu del_uu:0
退出。。。

请注意,在本例中,
\uu del\uu
是同步调用的。这种行为有语言保证吗?(请记住上面列出的假设。)

来自Python语言参考(Python 2.7.3版):

物体永远不会被明确摧毁;但是,当它们变得无法访问时,可能会被垃圾收集。一个实现可以推迟垃圾收集或完全忽略垃圾收集——只要没有收集到仍然可以访问的对象,垃圾收集是如何实现的是实现质量的问题

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


语言不能保证这种行为。例如,请参见其中明确说明在PyPy中调用
\uu del\uuu
的时间不同于CPython


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

您的用例是什么,答案很重要?如果我可以依赖此行为,它允许更干净的API设计。我不需要强迫我的库的用户记住对我给他们的对象调用一些特殊的“cleanUp()”函数,我只需要在del中添加必要的清理代码。例如,这是基于C++的优秀RAI API设计的本质。但是,知道DEL何时被调用会改变这个吗?(该对象在任何情况下都会在某个时候被删除)一个公平的问题;谢谢你提出来。在我现在的代码中,我有一个断言正在捕获某些对象的“遗忘”清理。这并不是绝对必要的;它只是用来捕捉程序员的错误(“你忘了什么吗?”)。如果我知道这个物体现在应该已经清理干净了,那么这是一张有效的支票。但是如果该对象可以合法地出现在某个“待办事项”列表中,那么我不能因为程序员还没有清理它而对其大喊大叫。很好的链接,谢谢。这给了我三个印象:(1)语言规范很模糊,但似乎暗示应该立即删除行为。(2) 这是一个武断的决定,可能是受CPython实现的影响。(3) 实际上,“官方”答案是什么并不重要,因为PyPy、Jython和IronPython的作者不会采用CPython的引用计数方案。这一事实意味着无论标准编写者是否关心,
\uuuu del\uuuu
行为实际上是“未定义”的。我不能说语言规范在这一点上是否不清楚,但从实际的角度来看,我同意行为是未定义的,不应该使用,除非您确实希望代码在对象从内存中删除时准确运行(这似乎是一个不太可能的用例)。另外,请注意:即使CPython是唯一的目标,我认为不应该编写假定对象不是引用周期的一部分的代码。由于对象本身的外部环境,对象可能成为引用周期的一部分。叹气。我怎么会错过呢?我花时间阅读了关于
\uu del\uu
本身的文档,但没有明确说明实现定义了什么。它只是说,
\uu del\uu
被称为“当x的引用计数达到零时调用”。但是你引用的这段话清楚地表明了这一点。接受这个答案,但也请参见@Andrew的答案(下文),以获取与PyPy讨论非常相关的链接。