Reference counting
coreintermediateEvery CPython object carries a count of how many references point at it. A new name, container slot, or argument binding increments it; del, rebinding, or scope exit decrements it. The object is freed the instant the count hits zero.
Think of it as
A ticket counter on a door: every time someone walks in (a new reference), it clicks up by one; every time someone leaves (a reference goes away), it clicks down. The room is cleared out the moment the counter reads zero — no waiting, no schedule, just that one number.
What we're doing: Track how binding a second name, passing an object to a function, and deleting names each change its reference count.
- 3
- obj = object() creates the object — one reference: the name obj.
- 4
- getrefcount adds its own temporary reference while running, so this reports 2, not 1.
- 6
- alias = obj adds a second, permanent reference.
- 7
- Now 3: obj, alias, plus getrefcount's temporary one.
- 10
- Calling hold(obj) binds a third name, x, for the duration of the call.
- 12
- Inside hold, refcount is 4: obj, alias, the parameter x, plus getrefcount's temporary reference.
- 14
- del alias removes one permanent reference, dropping the count back down.
2
3
4
2Why this works: Every reference to obj — a name, a function parameter, a container slot — adds one to its count, and every one that goes away subtracts one. sys.getrefcount always reports one more than the "real" number of long-lived references, because passing obj to it as an argument is itself a temporary reference that exists for the duration of the call. Calling hold(obj) adds a fourth reference (the parameter x) only while hold is running; that reference disappears when hold returns, though this example does not print after the call to show that drop.
Forgetting sys.getrefcount always overcounts by one
Wrong
Better
What you see: sys.getrefcount(obj) reports 2 for an object with exactly one real reference (the name obj) — reading that as "two references exist somewhere else" is the wrong conclusion.
Why: Calling sys.getrefcount(obj) passes obj as an argument, which itself is a reference that exists for the duration of the call — the function is, unavoidably, looking at a count that includes its own temporary hold on the object. Subtracting 1 gives the count that existed just before the call.
- obj = object() — refcount 1
- alias = obj — refcount 2 — a second reference
- del obj; del alias — refcount 0 — freed instantly
What changes the reference count
Together
Remember: Every object carries a refcount; freed the instant it hits zero. sys.getrefcount(obj) reports one extra, for its own reference. Alone, it cannot free a cycle.
See also: object lifecycle · garbage collection · cyclic references

