python的descrice函数 python中的del函数_引用计数


对象绝不会自行销毁;然而,无法得到对象时,可能会被当作垃圾回收。

del 语句删除名称,而不是对象。del 命令可能会导致对象被当作垃圾 回收,那是仅当删除的变量保存的是对象的最后一个引用,或者无法得到对象时2。重新绑定也可能会导致对象的引用数量归零,导致对象被销毁。

2如果两个对象相互引用,当它们的引用只存在二者之间时,垃圾回收程序会判定它们都无法获取,进而把它们都销毁。

有个 __del__ 特殊方法,但是它不会销毁实例,不应该在代码中调用。即将销毁实例时,Python 解释器会调用 __del__ 方法,给实例最后的机会,释放外部资源。自己编写的代码很少需要实现 __del__ 代码,有些 Python 新手会花时间实现,但却吃力不讨好,因为 __del__ 很难用对。

在 CPython 中,垃圾回收使用的主要算法是引用计数。实际上,每个对象都会统计有多少引用指向自己。当引用计数归零时,对象立即就被销毁:CPython 会在对象上调用 __del__ 方法(如果定义了),然后释放分配给对象的内存。CPython 2.0增加了分代垃圾回收算法,用于检测 引用循环中涉及的对象组——如果一组对象之间全是相互引用,即使再 出色的引用方式也会导致组中的对象不可获取。Python 的其他实现有更 复杂的垃圾回收程序,而且不依赖引用计数,这意味着,对象的引用数 量为零时可能不会立即调用 __del__ 方法。

为了演示对象生命结束时的情形,下例使用 weakref.finalize 注册一个回调函数,在销毁对象时调用。

没有指向对象的引用时,监视对象生命结束时的情形


>>> import weakref
# s1 和 s2 是别名,指向同一个集合,{1, 2, 3}。 
>>> s1 = {1, 2, 3}
>>> s2 = s1
# 这个函数一定不能是要销毁的对象的绑定方法,否则会有一个指向对象的引用。
>>> def bye():
...     print('Gone with the wind...')
...
# 在 s1 引用的对象上注册 bye 回调。 
>>> ender = weakref.finalize(s1, bye)
>>> ender.alive
True
>>> del s1
# 如前所述,del 不删除对象,而是删除对象的引用。 
>>> ender.alive
True
# 重新绑定最后一个引用 s2,让 {1, 2, 3} 无法获取。对象被销毁 了,调用了 bye 回调,ender.alive 的值变成了 False。 
>>> s2 = 'spam'
Gone with the wind...
>>> ender.alive
False
>>>


明确指出 del 不会删除对象,但是执行 del 操作后可能会导致对象不可获取,从而被删除。

你可能觉得奇怪,为什么示例中的 {1, 2, 3} 对象被销毁了?毕竟,我们把 s1 引用传给 finalize 函数了,而为了监控对象和调用回调,必须要有引用。这是因为,finalize 持有 {1, 2, 3} 的弱引用,参见下一节。