Mutable vs Immutable Objects in Python (Explained Simply)
Source: Dev.to
Introduction
This post explains a core Python concept that often causes confusion, especially when working with data structures, recursion, and backtracking. In Python, objects can be broadly classified into two categories based on whether their internal state can change:
- Mutable objects
- Immutable objects
Understanding this distinction is critical for writing correct and predictable Python code.
Mutable Objects
Mutable objects are objects whose contents can be changed after creation. When you modify a mutable object:
- The same object in memory is updated.
- The memory address does not change.
Common mutable types include list, set, and dict.
a = [1, 2, 3]
a.append(4)
print(a) # [1, 2, 3, 4]
In the example above, a still points to the same list, but the list’s contents are modified in place.
Immutable Objects
Immutable objects are objects whose contents cannot be changed after creation. Any operation that appears to modify them actually:
- Creates a new object.
- Assigns a new memory address.
Common immutable types include int, float, str, tuple, and frozenset.
x = 10
x = x + 1
print(x) # 11
What happened
- The integer
10was not modified. - A new integer
11was created. xnow points to the new object.
Effects of Mutability
The mutability of objects influences several aspects of Python programming:
- Function arguments – mutable arguments can be altered inside a function, affecting the caller’s variable.
- Recursion and backtracking – immutable objects make it easier to reason about state changes.
- Shared references – multiple variables can reference the same mutable object, leading to unexpected side effects.
Example: Mutable Argument
def add_item(lst):
lst.append(100)
nums = [1, 2, 3]
add_item(nums)
print(nums) # [1, 2, 3, 100]
The list nums changed outside the function because it is mutable.
Summary
- Mutable objects (e.g.,
list,set,dict) can be changed after creation and retain the same memory address. - Immutable objects (e.g.,
int,float,str,tuple,frozenset) cannot be changed; operations produce new objects with new addresses.
Keeping the mutable vs. immutable distinction in mind helps avoid many common bugs and saves hours of debugging.