最近注意到 Python 中有 __del__ 这个魔法函数,当一个对象被删除时会调用此函数。
那么这个删除具体是个什么概念呢?随即动手进行了些测试。
结论:当一个对象被 GC 回收时会调用其 __del__ 函数。
实验
背景
class Student:
def __init__(self, name):
self.name = name
def __del__(self):
print(f'deleting {self.name}')
case 1
In [4]: def test():
...: amy = Student('Amy')
...: del amy
...: print('exit')
...:
In [5]: test()
deleting Amy
exit
手动 del 后,自动触发了 __del__。
case 2
In [2]: def test():
...: amy = Student('Amy')
...: print('exit')
...:
In [3]: test()
exit
deleting Amy
即使没有调用 del,也触发了 __del__, 而且是在函数退出之后。
怀疑与 GC 有关,函数退出后,对象自动被 GC 回收,调用了 __del__。
case 3
In [6]: def test():
...: amy = Student('Amy')
...: students = [amy]
...: del amy
...: print('exit')
...:
In [7]: test()
exit
deleting Amy
手动调用 del 后,没有随即触发 __del__,而是在函数退出后调用。看来 __del__ 与 del 没有直接关系,而是和 GC 关系更大。
del 删除的是引用这个对象的字面量,或者说是将这个字面量和对象解绑。
实际对象由于被容器对象引用,所以并没有随即销毁,也就没有立刻触发 __del__。
case 4
In [8]: def test():
...: amy = Student('Amy')
...: amy = 1
...: print('exit')
...:
In [9]: test()
deleting Amy
exit
amy 字面量另指向其他对象,原对象不再被引用,于是被 GC 回收,触发 __del__。
结论
根据测试结果,有两种场景会触发其 __del__ 函数:
- 手动调用
del后,且对象不再被其他对象引用 - 对象不再被引用,被 GC 回收
准确来说后者包含前者,即 当一个对象被 GC 回收时会调用其 __del__ 函数。__del__ 与 del 没有直接关系。
彩蛋
那么如果把 GC 关掉,是不是就不会触发 __del__ 了呢?
In [2]: import gc; gc.disable()
In [3]: def test():
...: amy = Student('Amy')
...: print('exit')
...:
In [4]: test()
exit
deleting Amy
还是触发了 __del__,这是为什么呢?
不管关不关GC,程序退出的时候都得释放内存,所以始终都会触发 __del__ ,这是可以理解的。
那 gc.disable() 实际做了哪些事呢,看来还得好好看看 GC 呢。