Weak References
Weak References
Section titled βWeak ReferencesβWhat it is
Section titled βWhat it isβA normal reference to an object increases its reference count, keeping it alive as long as the reference exists. A weak reference (weakref module) refers to an object without incrementing its refcount β the object can still be garbage-collected even while a weak reference to it exists, at which point the weak reference simply reports the object is gone.
Before this feature
Section titled βBefore this featureβA cache that holds normal (strong) references to its values prevents those values from ever being garbage-collected, even after nothing else in the program needs them β silently growing memory usage forever unless you manually evict entries:
_cache = {}
def get_data(key, expensive_loader): if key not in _cache: _cache[key] = expensive_loader(key) return _cache[key]# _cache holds a strong reference to every value forever β# even objects nothing else references anymore stay aliveAfter this feature
Section titled βAfter this featureβimport weakref
class DataHolder: def __init__(self, value): self.value = value
d = DataHolder("some data")r = weakref.ref(d) # weak reference β doesn't keep d alive
print(r()) # <DataHolder object> -- call it to get the objectdel dprint(r()) # None -- the object was collected; the weakref reports it's gone# WeakValueDictionary: a cache that doesn't prevent garbage collectioncache = weakref.WeakValueDictionary()
def get_data(key, expensive_loader): if key in cache: return cache[key] obj = expensive_loader(key) cache[key] = obj # stored as a weak reference return obj# Entries disappear from the cache automatically once nothing else# references the value β no manual eviction needed, no memory leakWhy this is better
Section titled βWhy this is betterβ- Caches that donβt prevent cleanup:
WeakValueDictionary/WeakKeyDictionarylet you cache objects without being the reason they never get freed. - Breaks reference cycles deliberately: an observer pattern where children need to reference a parent can use a weak reference for the back-link, avoiding a strong reference cycle (parent β child β parent) that would otherwise rely on the cyclic garbage collector to clean up.
- Explicit about ownership: a weak reference in the code signals βI want to know about this object, but Iβm not whatβs keeping it aliveβ β clearer intent than a strong reference that happens to get cleared manually later.
Key notes / edge cases
Section titled βKey notes / edge casesβ- Not all objects support weak references β plain
int,str,list,dict, andtupleinstances cannot be weakly referenced directly (TypeError: cannot create weak reference); most custom classes can, unless they define__slots__without including'__weakref__'in it. weakref.ref(obj)is a callable βr()returns the object (orNoneif itβs been collected), it does not return the object directly.weakref.WeakValueDictionaryandWeakKeyDictionaryautomatically remove entries once the weakly-referenced object is garbage-collected β no explicit cleanup code needed.weakref.proxy(obj)is similar toref()but behaves like the object itself (transparent proxy) rather than requiring you to call it β accessing it after the object is gone raisesReferenceErrorinstead of returningNone.
Quick practice
Section titled βQuick practiceβ-
Does creating a weak reference to an object increase its reference count?
Answer
No β that's the entire point. A weak reference doesn't keep the object alive. -
What does
weakref.ref(obj)()return afterobjhas been garbage-collected?Answer
`None`. -
Why is
WeakValueDictionarya good fit for a cache?Answer
Cached values are automatically removed once nothing else references them, so the cache doesn't prevent garbage collection or grow unboundedly holding onto objects nobody needs anymore.