TOC

Python 弱引用

垃圾回收

Garbage Collector, 简写: GC

Python 垃圾回收是简单基于引用计数

弱引用

在计算机程序设计中,弱引用与强引用相对,是指不能确保其引用的对象不会被垃圾回收器回收的引用。一个对象若只被弱引用所引用,则被认为是不可访问(或弱可访问)的,并因此可能在任何时刻被回收。一些配有垃圾回收机制的语言,如Java、C#、Python、Perl、Lisp等都在不同程度上支持弱引用。

一句话:弱引用不增加计数,对引用计数型 GC 友好一些

垃圾回收与循环引用的问题

import gc

IDS = {}

class A:
    def __del__(self):
        _id = id(self)
        print('A.__del__ %s: 0x%x' % (IDS[_id], _id))

OBJS = {i: A() for i in range(3)}
for i, obj in OBJS.items():
    _id = id(obj)
    IDS[_id] = f'OBJS[{i}]'
    print('%s: 0x%x' % (IDS[_id], _id))
OBJS[1].attr = OBJS[1]
print('1' * 50)
print('====> del OBJS[0]')
del OBJS[0]
print('2' * 50)
print('====> del OBJS[1]')
del OBJS[1]
print('3' * 50)
print('====> del OBJS[2]')
del OBJS[2]
print('4' * 50)
gc.collect()
import weakref

print()
print('=' * 50)
class B:
    def __init__(self, obj):
        self.attrs = [obj]
    def __del__(self):
        _id = id(self)
        print('B.__del__ %s: 0x%x' % (IDS[_id], _id))
a = A()
b = B(a)
a.xyz = b
IDS[id(a)] = 'a'
IDS[id(b)] = 'b'
del a, b  # do nothing
print('=' * 40)
gc.collect()  # will del a and b

print()
print('=' * 50)
class C:
    def __init__(self, obj):
        self.attrs = [weakref.ref(obj)]
    def __del__(self):
        _id = id(self)
        print('C.__del__ %s: 0x%x' % (IDS[_id], _id))
a = A()
c = C(a)
a.xyz = c
IDS[id(a)] = 'a'
IDS[id(c)] = 'c'
del a, c
print('=' * 40)
gc.collect()

标准库:weakref

  • class weakref.ref(object[, callback]) 回调
  • weakref.proxy(object[, callback])
  • weakref.getweakrefcount(object)
  • weakref.getweakrefs(object)
  • class weakref.WeakKeyDictionary([dict])
  • .keyrefs()
  • class weakref.WeakValueDictionary([dict])
  • .valuerefs()
  • class weakref.WeakSet([elements])

    Set class that keeps weak references to its elements. An element will be discarded when no strong reference to it exists any more.

  • class weakref.WeakMethod(method)
  • class weakref.finalize(obj, func, /, *args, **kwargs)
  • weakref.ReferenceType
  • weakref.ProxyType
  • weakref.CallableProxyType
  • weakref.ProxyTypes
import weakref

class Klass:
    pass

obj = Klass()
ref = weakref.ref(obj)
print(ref())
del obj
print(ref())  # None

obj = Klass()
p = weakref.proxy(obj)
print(p)
del obj
print(p)  # ReferenceError: weakly-referenced object no longer exists

参考资料与拓展阅读