Show that an object stays alive while a reference to it exists and is collected once the last reference goes, using weakref.
CPython manages memory mainly with reference counting. Every object carries a counter that records how many references point at it. When you bind a name to an object, that counter goes up by one. When the name goes away, the counter goes down by one. The moment the counter reaches zero, the memory of the object is released right away and in a predictable way, with no waiting for a collection pass.
A weak reference lets you watch that happen without keeping the object alive yourself.
import weakref
class Node:
def __init__(self, name):
self.name = name
node = Node('payload')
ref = weakref.ref(node)
print('alive:', ref() is not None)
print('name:', ref().name)
del node # the last strong reference is gone
print('collected:', ref() is None)
The output is alive: True, then name: payload, and then collected: True. The object was freed the moment its reference count reached zero, so ref() now gives back nothing at all.
Weak references are used in real code for caches, for lists of observers, and for links between a parent and a child, where a strong reference would keep an object alive for ever. The standard library uses them as well. weakref.WeakValueDictionary is a dictionary that lets its values disappear, and weakref.finalize runs a cleanup action when an object is collected.
The important limitation is that a weak reference only works for types that support it. You cannot make a weak reference to an int or to a str, because those do not have an identity that you could meaningfully watch. You cannot weak-reference a tuple or a list either.