TL;DR
- 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 andis
for 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 None
for 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,is
for 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.
Top comments (11)
Can I connected with you?
Yes Sure :)
do you have discord?
Please tell me do you have discord, because Iam in a community of a developers.Thanks in advance.
Yep, I’m on Discord, happy to connect with you!
Here’s my username: anik7647
Feel free to add me anytime.
ok.
I have a question please, do you work on python or in the programmation?Thanks in advance.
I’m working with Python and JS, great tools for web dev.
Ok.Thanks.
Good project and inspiration.
Do you have any community?Thanks in advance.