奇怪的python析构函数行为

时间:2016-09-01 20:05:43

标签: 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。

1 个答案:

答案 0 :(得分:3)

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

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

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

>>> 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 xdel(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