🔁 Mutable vs Immutable in Python – A Deep Dive (With Mental Models)

Manas ShindeManas Shinde
3 min read

Understanding the difference between mutable and immutable objects in Python is foundational for writing efficient, bug-free code. This concept affects how variables behave, how functions handle arguments, and how memory is managed behind the scenes.

Let’s break it down clearly, with examples and memory models — no memorization needed.


✅ What Are Mutable and Immutable Objects?

In simple terms:

  • Mutable objects: Can be changed after they are created.

  • Immutable objects: Cannot be changed after creation.

Immutable TypesMutable Types
int, float, boollist, dict, set
str, tuple, bytesbytearray, array.array
frozensetCustom mutable classes

🧪 Example: Strings (Immutable)

username = "Manas"
print(username)  # Manas

username = "Bits of Python by Manas"
print(username)  #

Here’s what actually happens:

  • username = "Hitesh" → A string object is created in memory and username points to it.

  • username = "Chai aur Code" → A new string object is created, and username is now bound to that. The old string "Hitesh" is no longer referenced.

You didn’t modify the original string; you reassigned the variable.


🧪 Example: Integers (Immutable)

x = 10
y = x
x = 15

print(x)  # 15
print(y)  # 10

Even though y = x, modifying x later doesn't affect y.

Why? Because:

  • Integers are immutable.

  • When x = 15, a new object is created in memory and x now points to it.

  • y still points to the original 10.


🧪 Example: Lists (Mutable)

a = [1, 2, 3]
b = a
a.append(4)

print(a)  # [1, 2, 3, 4]
print(b)  # [1, 2, 3, 4]

Both a and b reference the same object. Since lists are mutable, modifying the object through one reference reflects in the other.


🧠 Behind the Scenes: Memory and Object Identity

In Python, everything is an object. Every object has:

  • Identity: Its memory address (check with id(obj))

  • Type: Like int, str, list, etc.

  • Value: The actual data it holds

When you assign a variable, you're creating a reference to an object — not copying the object itself.


⚠️ Gotcha: Mutable Default Arguments

def foo(bar=[]):
    bar.append(1)
    return bar

print(foo())  # [1]
print(foo())  # [1, 1]

The default list is shared across function calls! Always use None as the default:

def foo(bar=None):
    if bar is None:
        bar = []
    bar.append(1)
    return bar

🔁 Pass-by-Assignment in Python

Python’s function arguments are passed by assignment (also called "pass-by-object-reference"):

  • You pass a reference to the object, not the actual value.

  • Whether the function can modify the object depends on its mutability.

def modify_list(lst):
    lst.append(10)

my_list = [1, 2]
modify_list(my_list)
print(my_list)  # [1, 2, 10]

But with immutable types:

def change_number(n):
    n = n + 1

x = 5
change_number(x)
print(x)  # 5 (unchanged)

🗑️ Garbage Collection

When no variable refers to an object anymore, Python will automatically clean it up:

name = "Manas"
name = "Bits of Python by Manas"
# "Manas" is now unreferenced → garbage collected

🧰 Tools and Tips

  • Use id(obj) to check if two variables refer to the same object.

  • Use copy() or deepcopy() when working with mutable types and you need independent copies.

  • Convert lists to tuples when immutability is preferred.

  • Be careful when passing mutable objects to functions.


🧠 Key Takeaway

It’s not just about whether you can "change a value." It’s about whether the object in memory can be altered without creating a new one.

If yes → it’s mutable.
If no → it’s immutable.


💬 Over to You

Which part of mutable vs immutable tripped you up when learning Python? Ever hit a bug because of it? Share your thoughts in the comments!



Thanks You!

Manas Shinde

0
Subscribe to my newsletter

Read articles from Manas Shinde directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Manas Shinde
Manas Shinde