Python: Behind the Scenes — Mutable, Immutable, and the Secret Life of Objects 🧬
Have you ever thought you understood variables in Python… until your code started acting like it had a mind of its own? Welcome to the world of object identity, mutability, and the quirks that make Python both elegant and sometimes, surprisingly tricky.
Introduction
During my journey with Python, one lesson kept coming back: everything is an object. Integers, strings, lists, functions—even types themselves. At first, that seemed like a philosophical detail, but after a few “why is my list changing everywhere?” bugs, I realized it’s the foundation for understanding Python’s logic.
id and type: The DNA of Python Objects
Each Python object has two invisible tattoos: its type and its identity.
a = 42
print(type(a)) # <class 'int'>
print(id(a)) # 140022095219440 (unique per object)
If two variables have the same id, they’re two names for the same object. Otherwise, they’re just twins.
Mutable Objects: The Shapeshifters
Some objects in Python can change their state after creation. Lists, dictionaries, and sets are the most common examples.
my_list = [1, 2, 3]
my_list.append(4)
print(my_list) # [1, 2, 3, 4]
You can modify my_list in place, and any variable referencing it will see the change.This can be both powerful and, if you’re not careful, a source of weird bugs!
Immutable Objects: The Frozen Ones
Integers, strings, and tuples are immutable—once created, they can’t be changed.
a = "BestSchool"
b = a
a = "Holberton"
print(b) # "BestSchool"
When you try to change them, Python creates a new object instead. The old one stays as it was, safe from modification.
Why Does This Matter? Python’s Split Personality
Python treats mutable and immutable objects differently, especially when it comes to assignment and function arguments.
This distinction impacts how variables behave and how data flows in your program.
How Python Passes Arguments: Reference, But Not Quite…
When passing variables to functions, Python always passes the reference to the object—not a copy.But what happens next depends on mutability:
Example 1: Immutable Argument
def update_number(n):
n += 1
a = 10
update_number(a)
print(a) # 10
The integer doesn’t change—n += 1 creates a new int.
Example 2: Mutable Argument
def update_list(lst):
lst.append(4)
my_list = [1, 2, 3]
update_list(my_list)
print(my_list) # [1, 2, 3, 4]
The list is changed in place!
If you want to avoid side effects, always be aware of whether your data is mutable or immutable.
Advanced: Tuples, Copies, and Gotchas
One of the trickiest details:Tuples are immutable, but they can contain mutable objects.
t = ([1, 2, 3],)
t[0].append(4)
print(t) # ([1, 2, 3, 4],)
So the tuple doesn’t change, but its content might!
And beware shallow vs deep copies:
import copy
a = [[1, 2], [3, 4]]
b = a.copy() # Shallow copy
c = copy.deepcopy(a) # Deep copy
Takeaways
💬 Thank you for reading this post!Feel free to react or connect if you’d like to discuss Python, coding, or share your own tips.