- Variables in Python are names pointing to objects in memory, not boxes that store values.
- CPython uses reference counting + a cycle-detecting garbage collector.
- Mutable vs immutable objects change how reassignment and function calls behave.
- Use
==for value equality andisfor identity checks. - CPython optimizes small ints and strings through interning and performs constant folding at compile time.
1) Variables Are Names, Not Boxes
Most beginners imagine variables as “containers” holding values. In Python, a variable is actually a name that references an object in memory.
Think: Name → Object (type, value, refcount)
2) Memory References in Python
Assigning a variable binds a name to an object:
x = 10 y = x # y points to the same object as x print(x, y) # 10 10 print(id(x), id(y)) # same identity
Rebinding creates a new link:
x = [1, 2, 3] y = x y.append(4) print(x) # [1, 2, 3, 4]
Why it matters: Mutating objects via one name can affect other names referencing the same object.
3) Reference Counting in CPython
CPython tracks how many references point to an object. When the count hits 0, the object is deallocated.
import sys a = [1, 2, 3] print(sys.getrefcount(a)) # +1 due to temporary reference in function b = a print(sys.getrefcount(a)) # increased del b print(sys.getrefcount(a)) # back down
Note: PyPy and other Python implementations use different GC strategies.
4) Garbage Collection & Cycles
Reference counting alone can’t reclaim cycles (A → B → A). Python’s cycle collector handles this:
import gc class Node: def __init__(self): self.ref = None a, b = Node(), Node() a.ref, b.ref = b, a del a, b collected = gc.collect() print("Collected:", collected)
Tip: Avoid __del__ in cyclic objects; it can delay collection.
5) Dynamic vs Static Typing
Python is dynamically typed (names can point to any type) and strongly typed (no silent coercion):
x = 10 x = "ten" # fine # x + 5 # TypeError
Type hints help humans and IDEs, not the interpreter.
6) Variable Reassignment
Reassignment changes the binding, not the object:
x = 10 old_id = id(x) x = 20 print(old_id == id(x)) # False
For mutable objects, you can mutate or rebind:
nums = [1, 2] nums = nums + [3] # new list nums.append(4) # same list
7) Mutability Explained
- Immutable: int, float, bool, str, tuple, frozenset
- Mutable: list, dict, set
s = "hi" s += "!" # new string object d = {"a":1} d["b"] = 2 # same dict object
Tuples can contain mutable objects:
t = ([], 42) t[0].append("boom") print(t) # (['boom'], 42)
8) Functions, Arguments & Mutability
Python passes object references to functions:
def mutate(lst): lst.append(99) def rebind(lst): lst = lst + [99] a = [1, 2, 3] mutate(a) # [1, 2, 3, 99] rebind(a) # still [1, 2, 3, 99]
Avoid mutable default arguments:
def good(x, bucket=None): if bucket is None: bucket = [] bucket.append(x) return bucket
9) Shared References Gotchas
Two names referencing the same mutable object share changes:
a = [1,2]; b = a; b.append(3) print(a) # [1,2,3]
Copy carefully:
import copy x = [[1],[2]] y = copy.copy(x) # shallow z = copy.deepcopy(x) # deep
10) Equality: == vs is
-
==→ value equality -
is→ identity (same object)
x = [1,2,3]; y = [1,2,3] print(x==y, x is y) # True, False a = None; b = None print(a is b) # True
Use
is Nonefor sentinel checks.
11) Everything is an Object
Names live in namespaces (dict-like):
x = 42 def f(): pass print(type(x), type(f)) print(globals().keys())
LEGB rule: Local → Enclosing → Global → Builtin
12) CPython Optimizations: Integer Interning
Small integers are often shared:
a = 256; b = 256 print(a is b) # True a = 257; b = 257 print(a is b) # Might be False
13) CPython Optimizations: String Interning
Compile-time literals and identifiers may be interned:
import sys u = "".join(["status","_ok"]) v = "".join(["status","_ok"]) print(u is v) # False u = sys.intern(u); v = sys.intern(v) print(u is v) # True
14) Constant Folding & Peephole Optimizations
Python precomputes simple expressions at compile-time:
x = 2*10 # folded to 20 y = ("a"+"b") # folded to "ab"
import dis def demo(): return 2*10 dis.dis(demo)
Big-O matters more than peephole tricks.
Quick Checklist
- [ ] Names point to objects, not values.
- [ ]
==for value,isfor identity. - [ ] Mutables vs immutables.
- [ ] Avoid mutable defaults.
- [ ] Copy carefully (
copy()vsdeepcopy()). - [ ] Refcount + GC for cycles.
- [ ] Interning is an optimization detail.
- [ ] Clarity > micro-optimizations.
Wrap-Up
The golden rule: Python names point to objects. Once you internalize that, mutability, GC, equality, and optimization behavior all make sense.
Source: DEV Community.

Leave a Reply