The Python Object Model, Explained Like You've Never Coded Before
When you first start coding, you treat Python like a calculator. You type x = 5, then y = x + 2, and you get 7. It feels like you are just pushing raw numbers around.
But eventually, things start acting weird. You try to append something to a list inside a function, and suddenly the original list outside the function changes. You realize there is an invisible machine operating behind the scenes, following rules nobody explicitly told you about.
To move from writing scripts that work to writing systems you understand, you need to look at the machine itself: the Python Object Model. You need to understand the lifecycle of the data you create.
Same approach as always — why first, then what, then code.
🌌 Everything is an Object
In some languages, a number like 5 is just a raw piece of electronic memory. It has no features, no identity—it’s just a raw value.
In Python, there is no raw data. Literally everything is an object. A number is an object. A string is an object. A list is an object. Even the function you write to process the list is an object.
Analogy: Imagine a hardware store. In other languages, a nail is just a loose piece of metal sitting in a bin. In Python, every single nail is individually packaged in a tiny plastic blister pack. Printed on that packaging is a serial number, a manual on how to use it, and a sticker indicating exactly what material it's made of.
Because everything is packaged up (an object), you can ask anything in Python to introduce itself and explain its capabilities.
🧬 The Object Trinity: Identity, Type, and Value
Every time you create an object in Python, it is born with three fundamental characteristics. Think of this as the object's soul.
1. Object Identity (The "Where")
When an object is created, it takes up physical space in your computer's RAM. Its Identity is the exact memory address where it lives. Once an object is born, its identity never changes until it is destroyed.
You can look up this address using the id() function.
x = 42
print(id(x)) # Outputs a massive number like 140726194726984
Analogy: This is the exact GPS coordinate of the object's house. You might give the object different nicknames (variables), but the GPS coordinate remains the exact same.
2. Object Type (The "What")
The Type dictates the blueprint of the object. It decides what the object is allowed to do. Can it be added? Can it be sliced? Can it be called like a function? Like identity, an object's type never changes. A number cannot suddenly become a list.
name = "Aman"
print(type(name)) # <class 'str'>
Analogy: The type is the object's DNA or species. A dog (str) can bark (.upper()), but it cannot fly. A bird (list) can fly (.append()), but it cannot bark.
3. Object Value (The "Contents")
The Value is the actual data stored inside the object.
If the object is mutable (like a list or dictionary), you can change its value without changing its identity. You are rearranging the furniture inside the same house.
If the object is immutable (like an integer, string, or tuple), its value is locked forever. If you want a new value, Python destroys the old house and builds a new one entirely.
# Mutable example
my_list = [1, 2, 3]
print(id(my_list)) # Address A
my_list.append(4) # The value changes!
print(id(my_list)) # Address A -> The exact same list in memory.
🎈 Reference Counting
So, you create thousands of objects while your program runs. Why doesn't your computer run out of memory and crash?
Because Python is obsessively tracking how many variables care about an object. This is called Reference Counting.
Every time you create a variable and point it to an object (x = [1, 2, 3]), Python attaches an invisible string from the variable name x to the list object in memory. It increments that object's "reference count" to 1. If you say y = x, it attaches a second string. The count is now 2.
import sys
my_data = ["valuable", "information"]
# getrefcount always returns 1 higher because passing it to the function creates a temporary reference
print(sys.getrefcount(my_data)) # Count is 2
Analogy: Imagine objects as helium balloons. Variables are the strings holding them down. As long as at least one person is holding a string, the balloon stays grounded and safe.
🗑️ Garbage Collection
What happens if you delete a variable, or if a function finishes running and its variables disappear? The strings are cut.
The moment an object's reference count drops to zero—meaning absolutely no variable in your entire program is pointing to it anymore—the balloon flies away. Python's memory manager immediately steps in, destroys the object, and frees up that space in your RAM.
This happens instantly and silently. It is the causality of memory management: no references = no existence.
The Cyclic Reference Trap
If reference counting is so perfect, why does Python also have a dedicated system called the Garbage Collector (GC)?
Because of the "Island of Isolation" problem.
list_a = []
list_b = []
# They point to each other!
list_a.append(list_b)
list_b.append(list_a)
# Now we delete our connection to them
del list_a
del list_b
Analogy: You tied balloon A's string to balloon B, and balloon B's string to balloon A. Then, you let go of both. Neither balloon has a reference count of zero (they are holding each other), but you have no way to reach them ever again. They are floating in the sky, taking up space, completely useless.
Python's Garbage Collector periodically pauses your program for a fraction of a millisecond, scans memory looking for these isolated islands of cyclic references, and violently pops them to reclaim your memory.
🔄 The Object Lifecycle (Tying it Together)
To think like a veteran Python developer, you trace the chain of causality from birth to death:
Birth: You request data (
x = 10). Python finds an empty plot of land in RAM, assigns it an Identity (Address), sets its Type (Integer), and fills its Value (10).Life: You pass this object into functions, assign it to new variables, or put it inside lists. Its Reference Count goes up and down as strings are tied and untied.
Death: The program moves on. The variables pointing to the object are reassigned or deleted. The reference count hits
0. Python instantly reclaims the memory, erasing the object from existence.
Understanding this model changes how you code. You stop worrying about variables as containers, and start seeing them as temporary nametags placed on a bustling, highly-managed universe of objects.

