我正在研究python3。我遇到了一个奇怪的情况,只有当一个对象有办法判断是否有任何引用时才能解释。但是,这种行为似乎不会影响python2.7。我已经放弃了它作为垃圾收集问题的解释,因为gc.disable()
没有任何区别。只是为了澄清,这对我来说不是问题,但我真的很想知道到底发生了什么。
如果您对特定情况感兴趣,可以使用MWE。
我正在处理从matplotlib docs剪贴的代码(matplotlib 2.0.0):
import matplotlib.pyplot as plt
import numpy as np
from datetime import datetime
def update_title(axes):
axes.set_title(datetime.now())
axes.figure.canvas.draw()
fig, ax = plt.subplots()
x = np.linspace(-3, 3)
ax.plot(x, x*x)
timer = fig.canvas.new_timer(interval=100)
timer.add_callback(update_title, ax)
timer.start()
#timer_another_ref = timer
#timer = None
plt.show()
现在,如果我取消注释行timer = None
,则计时器不再起作用(仅在python3中,正如我之前所说)。另一方面,如果我现在取消注释另一行,它会按预期工作。
作为旁注,我有两台电脑。一个是在ubuntu 14.04上运行python 3.4.3并使用后端Qt5Agg,另一个是在ubuntu 16.04上运行python 3.5.2并使用后端TkAgg。这种行为只能在前者上观察到(我猜它与后端有关)。
答案 0 :(得分:2)
如果要获取对象的引用计数,则可以使用:
sys.getrefcount(something)
请注意,以下内容会输出2
,因为它是对列表的临时引用。
lst = [1, 2, 3]
print(sys.getrefcount(lst))
答案 1 :(得分:1)
啊,它(几乎可以肯定)是由于垃圾收集。在CPython中,大量的垃圾收集是通过引用计数完成的,这与gc
模块无关。 gc
只需要在参考周期中收集垃圾,在这种情况下,单独引用计数是无能为力的。例如:
class T:
def __del__(self):
print("going away")
t = T()
print("before")
t = None # remove only reference to the object
print("after")
在每个发布的CPython版本(即使是gc
之前存在的版本)下,打印出来:
before
going away
after
现在变得更加漂亮:
x = T()
y = T()
x.ref = y
y.ref = x
print("before")
x, y = None, None
print("after")
import gc
gc.collect()
print("after gc")
x
代表y
,反之亦然。这是“一个循环”。每个都可以从另一个访问,因此他们的引用计数永远不会低于1(除非x.ref
和/或y.ref
也反弹)。因此,在所有版本的CPython下,打印出来:
before
after
起初。在Python 3下,它继续打印:
going away
going away
after gc
但在Python 2下它只会继续打印:
after gc
这是由于使用__del__
方法的循环垃圾包含对象的模糊技术问题; Python 2无法回收它们,但Python 3可以。
唉,我不可能完全猜出你的例子中发生了什么。这需要在两个实现下研究fig.canvas.new_timer
的源代码。
但是底线很清楚:如果你需要一个对象来保持活着,请确保它可以从你的代码中获得。在无法访问之后,一个垃圾收集子系统或其他垃圾收集系统随时可以自由销毁它。