(十六)引用关系、对象存活与资源关闭
1. 删除名称不等于关闭对象
# 普通名称与绑定方法都能保留对象引用;del 只移除指定的名称绑定。
class ReadingSession:
def __init__(self):
self.opened = True
def close(self):
self.opened = False
session = ReadingSession()
alias = session
close_later = session.close
del session
print(alias.opened)
del alias
# 方法对象仍然保留 __self__,所以现在还能关闭原来的实例。
close_later()
print(close_later.__self__.opened)输出 True False。删去 session 后,alias 与 close_later 还保留对象;删去 alias 后,绑定方法仍保留它。调用 close_later() 才真正执行本例的关闭动作。
对象使用的内存与外部资源的关闭是两件事。__del__ 是对象终结时的特殊方法,不能把它理解为 del 名称 的直接回调。需要在一段处理结束时关闭资源,沿明确的 close() 或 with 过程执行,调用顺序才与业务处理相对应。
2. 循环引用与垃圾回收
两个对象可以互相引用,一个对象也可以引用自身。删去外面的名称后,这样的引用环仍可能存在。CPython 除了引用计数,还用垃圾回收器处理不再从外部可达的循环结构。
# weakref.ref 建立不负责维持对象存活的弱引用,用于观察回收后的状态。
import gc
import weakref
class Link:
def __init__(self):
self.next = None
node = Link()
node.next = node
watch = weakref.ref(node)
del node
# 显式进行一次循环垃圾回收,不把回收数量当作固定结果。
gc.collect()
print(watch() is None)输出 True。watch() 在对象仍存活时可以取得它,回收后得到 None;弱引用本身不会为了观察而把对象一直留住。实际程序一般让解释器安排回收,不需要给每次对象创建都手动配一条 gc.collect()。弱引用、循环垃圾回收
图中先移除外部名称,留下节点对自身的引用;弱引用只负责观察。显式回收处理这个不再从外部可达的结构,之后观察结果变为 None。