python - 奇怪的Python析构函数行为

标签 python oop garbage-collection

在使用 OO Python 时,我遇到了以下好奇心。考虑以下简单的类:

>>> class Monty():
    def __init__(self):
        print 'start m'
    def __del__(self):
        print 'deleted m'

实例化对象按预期进行:

>>> a = Monty()
start m
>>> a
<__main__.Monty instance at 0x7fdf9f084830>

现在有趣的部分是:

>>> del a
>>> a = Monty()
start m
>>> a
deleted m
<__main__.Monty instance at 0x7fdf9f083fc8>
>>> a
<__main__.Monty instance at 0x7fdf9f083fc8>
>>> del a
>>> a = Monty()
start m
>>> del(a)
deleted m
>>> a = Monty()
start m
>>> a
deleted m
<__main__.Monty instance at 0x7fdf9f084830>

这里令人困惑的部分是我从析构函数中收到延迟的消息。我的理解是:

del a

删除对象引用,以便将对象 a 留给垃圾回收。但由于某种原因,解释器等待将消息传递到控制台。

另外这就是区别

del x

del(x)

因为如果您使用后者运行代码,则一切都会按预期进行 - 您可以从析构函数获得即时信息。

可以在 Python 2.7 以及使用 Python 3.3 上重现此内容。

最佳答案

Python 解释器创建一个附加引用。每次表达式不返回 None 时,结果都会被回显存储在 _ 内置名称中。

当您回显不同的结果时,_ 会反弹到新结果,并且旧对象引用计数会下降。在您的情况下,这意味着只有这样才会收获前一个 Monty() 实例。

换句话说,当您执行del a时,您并没有删除最后一个引用。只有当您稍后回显对象时,最后一个引用才会消失:

>>> a = Monty()   # reference count 1
start m
>>> a             # _ reference added, count 2
<__main__.Monty instance at 0x7fdf9f084830>    
>>> del a         # reference count down to 1 again
>>> a = Monty()
start m
>>> a             # _ now references the new object, count drops to 0
deleted m         # so the old object is deleted.
<__main__.Monty instance at 0x7fdf9f083fc8>

您可以通过回显 _ 来查看引用,并且可以通过回显完全不相关的内容来清除引用:

>>> a = Monty()   # reference count 1
start m
>>> a             # echoing, so _ is set and count is now 2
<__main__.Monty instance at 0x1056a2bd8>
>>> _             # see, _ is referencing the same object
<__main__.Monty instance at 0x1056a2bd8>
>>> del a         # reference count down to 1
>>> _             # _ is still referencing the result
<__main__.Monty instance at 0x1056a2bd8>
>>> 'some other expression'    # point to something else
deleted m                      # so reference count is down to 0
'some other expression'
>>> _
'some other expression'

del x 和 del(x) 之间没有区别。两者都执行 del 语句,括号是表达式的一部分,在这种情况下是无操作。没有 del() 函数。

真正的区别在于您没有在该代码部分中回显a,因此没有创建额外的_引用。

无论是否使用 (..) 括号,您都会得到完全相同的结果:

>>> a = Monty()  # ref count 1
start m
>>> del a        # no _ echo reference, so count back to 0
deleted m
>>> a = Monty()  # ref count 1
start m
>>> del(a)       # no _ echo reference, so count back to 0
deleted m

关于python - 奇怪的Python析构函数行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39280050/

相关文章:

python - 具有条件规则的 Pandas Dataframe

python - 转换为 float 时出错,然后在 python 中转换为 int

java - 创建子对象,子构造函数不使用OOP

javascript - Node.js 的垃圾收集器

Python os.getcwd() 在路径中返回波浪号。例如C :\MYFOLD~1\test

python - 使用非常重尾的数据在 Pandas 中绘制直方图

c# - "Base b = new Derived()"是哪个 OO 概念的一个例子?

python - Django python - 类属性值是否在请求之间共享?

java - Hotspot的scavenge GC停止运行,只剩下mark-sweep GC

java - 我如何对 GC 进行单元测试?