Skip to content

Weak References

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.

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 alive
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 object
del d
print(r()) # None -- the object was collected; the weakref reports it's gone
# WeakValueDictionary: a cache that doesn't prevent garbage collection
cache = 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 leak
  • Caches that don’t prevent cleanup: WeakValueDictionary/WeakKeyDictionary let 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.
  • Not all objects support weak references β€” plain int, str, list, dict, and tuple instances 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 (or None if it’s been collected), it does not return the object directly.
  • weakref.WeakValueDictionary and WeakKeyDictionary automatically remove entries once the weakly-referenced object is garbage-collected β€” no explicit cleanup code needed.
  • weakref.proxy(obj) is similar to ref() but behaves like the object itself (transparent proxy) rather than requiring you to call it β€” accessing it after the object is gone raises ReferenceError instead of returning None.
  1. Does creating a weak reference to an object increase its reference count?

    AnswerNo β€” that's the entire point. A weak reference doesn't keep the object alive.
  2. What does weakref.ref(obj)() return after obj has been garbage-collected?

    Answer`None`.
  3. Why is WeakValueDictionary a good fit for a cache?

    AnswerCached 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.