Skip to main content

Lib/weakref.py

cpython 3.14 @ ab2d84fe1023/Lib/weakref.py

Lib/weakref.py builds the higher-level weak reference types on top of _weakref (a C extension). The C module provides raw ref() and proxy(); this file adds WeakValueDictionary, WeakKeyDictionary, WeakSet, and finalize.

Map

LinesSymbolRole
1-50Re-exports from _weakrefref, proxy, getweakrefcount, getweakrefs
51-300WeakValueDictionaryDict with weak values; callback removes dead entries
301-450WeakKeyDictionaryDict with weak keys; callback removes dead entries
451-540WeakSetSet with weak members
541-620finalizeRun a callback when an object is GC'd

Reading

WeakValueDictionary dead-entry removal

Each value is stored as ref(value, callback) where callback removes the key from the dict. Because the callback fires during GC, it must be careful not to acquire locks that might be held by the main thread; WeakValueDictionary uses a KeyedRef subclass that stores the key alongside the ref so the callback can find and remove it.

# CPython: Lib/weakref.py:135 WeakValueDictionary.__init__
def __init__(self, other=(), /, **kw):
def remove(wr, selfref=ref(self), _atomic_removal=_remove_dead_weakref):
self = selfref()
if self is not None:
...
_atomic_removal(d, wr.key)
self._remove = remove

finalize

finalize(obj, func, *args, **kwargs) registers a func(*args, **kwargs) callback to be called when obj is garbage collected. Unlike __del__, finalize works on any object and can be cancelled via finalize.detach().

# CPython: Lib/weakref.py:550 finalize.__call__
def __call__(self, _=None):
info = self._registry.pop(self._key, None)
if info is not None:
return info.func(*info.args, **info.kwargs)

Thread safety in WeakKeyDictionary

WeakKeyDictionary uses _IterationGuard as a context manager around iteration to prevent the callback from modifying the underlying dict while it is being iterated. Pending removals are deferred until the iteration is done.

gopy notes

module/weakref/module.go provides basic ref() support. WeakValueDictionary, WeakKeyDictionary, and finalize are not yet ported. In Go, weak references will use runtime.SetFinalizer as the underlying primitive.