导入
固执的 del 操作
理解 del 如何通过引用计数决定 __del__ 何时调用
删除操作为何会如此复杂?
1class SomeClass: 2 def __del__(self): 3 print("Deleted!")
1.
让我们在交互式解释器中删除 SomeClass() 对象。
1>>> x = SomeClass() 2>>> y = x 3>>> del x # 这里应该打印 "Deleted!" 4>>> del y 5Deleted!
Terminal
终于删掉了。你可能已经猜到,在我们第一次尝试删除 x 时,是什么阻止了 __del__ 被调用。
2.
让我们让这个例子更复杂一些。
1>>> x = SomeClass() 2>>> y = x 3>>> del x 4>>> y # 检查 y 是否仍然存在 5<__main__.SomeClass instance at 0x7f98a1a67fc8> 6>>> del y # 和之前一样,这应该打印 "Deleted!" 7>>> globals() # 哦,它没有打印。我们检查一下所有全局变量来确认 8Deleted! 9{'__spec__': None, '__builtins__': <module 'builtins' (built-in)>, '__doc__': None, '__name__': '__main__', '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__package__': None, 'SomeClass': <class '__main__.SomeClass'>}
Terminal
解释
-
del x并不会直接调用x.__del__()。 -
当执行
del x时,Python 会从当前作用域中删除名称x,并将该对象的引用计数减 1。只有当对象的引用计数变为零时,才会调用__del__()。 -
在第二次输出中,
__del__()没有被调用,是因为前一条语句(>>> y)在交互式解释器中创建了对该对象的另一个引用(具体来说是_这个魔法变量,它指向上一个非None表达式的返回值),从而阻止了引用计数在执行del y时归零。

- 调用
globals()(或任何产生非None结果的操作)导致_引用了新的结果,从而丢弃了原有的引用。这一次,引用计数真正降到了 0,我们终于看到了 “Deleted!” 的输出。