A weak reference observes a supported object without keeping that object alive solely through the reference.
Python weak references: a cache does not own its values
Operation contract
The receipt cache uses weak values. The caller owns the record through a strong reference; the cache only helps find it while it remains alive. Deleting that owner and collecting unreachable objects leaves no cached value. This cache cannot promise retention between two separate lookups.
Failure and ownership boundary
Retrieve a weak value once into a local strong reference before using it. Testing membership and then fetching again creates a lifetime gap. Many built-in values cannot be weakly referenced directly. Weak references are also unsuitable for resource cleanup guarantees; Python ExitStack: unwind partially acquired resources controls acquired resources independently of garbage collection.
Working program
import gc
from weakref import WeakValueDictionary
class ReceiptRecord:
def __init__(self, receipt_id):
self.receipt_id = receipt_id
cache = WeakValueDictionary()
owned_record = ReceiptRecord("R-0041")
cache[owned_record.receipt_id] = owned_record
print(cache.get("R-0041") is owned_record)
del owned_record
gc.collect()
print(cache.get("R-0041") is None)Output
True
TrueCosts and limits
The cache retains keys and weak-reference bookkeeping rather than owning the entire value graph. Collection timing is interpreter-dependent. This fixture calls collection explicitly; production code must tolerate a value disappearing whenever no strong owner remains.
Common Mistakes
- A weak cache is not a durable store or retention promise.
- Hold the retrieved value locally instead of checking membership and fetching later.
Connected lessons
Python slots: attribute layout without deep immutability, Python variables: names refer to objects, assignment does not copy, Python ExitStack: unwind partially acquired resources.
Follow the service contract
Python tracemalloc: distinguish retained Python allocations from a process memory claim.
