Python __del__() 语法
__del__() 是 Python 的一个特殊方法(又称 “魔法方法” 或 “双下划线方法”), 它在对象被垃圾回收前自动调用,用于执行清理工作。
语法:
class MyObject:
def __del__(self):
# 执行清理操作
# 释放资源等
说明:
__del__() 方法不接收任何参数,除了 self(实例本身)。它不应返回任何值。
注意:
- __del__() 方法的调用时机是不确定的,Python 的垃圾回收机制决定了何时回收对象。
- 强烈建议避免在 __del__() 中处理复杂的逻辑或可能引发异常的操作,因为异常在析构器中可能会导致程序崩溃或不可预测的行为。
Python __del__() 摘要
| 属于 | Python 魔法方法 |
|---|---|
| 使用频率 | 低 |
| 官方文档 | 查看 |
Python __del__() 示例
接下来,我们通过几个简单的例子来讲解一下 Python __del__() 方法是如何使用的。
示例 1:__del__() 的调用时机
import gc
class MyResource:
def __init__(self, name):
self.name = name
print(f'“{self.name}” 已创建')
def __del__(self):
print(f'“{self.name}” 被销毁')
# 创建实例
res1 = MyResource('文件A')
res2 = MyResource('连接B')
# 显式删除引用(引用计数减 1)
del res1
# 此时 res2 仍然存在,当程序结束或所有引用消失时才会被销毁
print('程序即将结束')
# 强制执行垃圾回收(不推荐在生产代码中频繁使用)
gc.collect()
print('强制垃圾回收完成')
运行结果如下。
“文件A” 已创建
“连接B” 已创建
“文件A” 被销毁
程序即将结束
强制垃圾回收完成
“连接B” 被销毁
分析:
当 del res1 执行时,res1 对象的引用计数变为 0(假设没有其他引用),其 __del__() 方法会被立即调用。对于 res2 来说,在程序正常结束时(或者当垃圾回收器认为它不再被需要时),它的 __del__() 方法才会被调用。
从这个例子也可以看出,__del__() 的调用时机是不确定的,不像 __init__() 那样严格绑定到对象创建。
示例 2:__del__() 与循环引用
class Node:
def __init__(self, value):
self.value = value
self.next = None
self.prev = None
print(f'节点 “{self.value}” 被创建')
def __del__(self):
print(f'节点 “{self.value}” 被销毁')
def create_circular_reference():
a = Node('A')
b = Node('B')
a.next = b
b.prev = a
print('创建循环引用:A <-> B')
return a, b
# 创建循环引用
nodeA, nodeB = create_circular_reference()
# 删除外部引用
del nodeA
del nodeB
print('外部引用已删除')
# 此时,NodeA 和 NodeB 的 __del__() 可能不会立即被调用,因为它们之间存在循环引用。
# Python 的分代垃圾回收器最终会处理它们,但时机不确定。
import gc
print('强制垃圾回收开始')
gc.collect()
print('强制垃圾回收完成')
运行结果如下。
节点 “A” 被创建
节点 “B” 被创建
创建循环引用:A <-> B
外部引用已删除
强制垃圾回收开始
节点 “A” 被销毁
节点 “B” 被销毁
强制垃圾回收完成
分析:
即使删除了 nodeA 和 nodeB 的外部引用,如果它们之间形成循环引用,它们的引用计数可能不会降到 0。在这种情况下,__del__() 便不会立即被触发。
Python 的分代垃圾回收器会周期性地检测并回收这些循环引用的对象,因此 __del__() 最终仍会被调用,但其时机变得更加不可预测。
