Mutable vs Immutable Data Types in Python
In Python, every value is an object, and every object is classified as either mutable or immutable based on whether its internal state can be modified after creation. Understanding this distinction is fundamental for writing bug-free code, managing memory efficiently, and avoiding unexpected side effects when passing data to functions. This article breaks down what mutable and immutable types are, lists common examples of each, and highlights the critical behavioral differences between them.
What Does Mutability Mean?
An object's mutability determines whether its contents can be altered
in-place without changing its identity (its memory address, accessed via
the id() function).
- Mutable Objects: Can be modified after creation. You can add, remove, or update elements without Python allocating a new memory address for the object itself.
- Immutable Objects: Cannot be changed once instantiated. Any operation that appears to alter an immutable object actually generates an entirely new object in memory with a new identity.
Common Python Data Types by Category
Python categorizes its standard built-in data types strictly into mutable or immutable sets:
Mutable Data Types:
listdictsetbytearray
Immutable Data Types:
int,float,complexstrtupleboolfrozensetbytes
Key Differences in Practice
1. In-Place Modification vs. Reallocation
When you append an item to a list, the original list updates in
place, preserving its id():
numbers = [1, 2, 3]
old_id = id(numbers)
numbers.append(4)
print(id(numbers) == old_id) # Returns TrueIn contrast, modifying a string creates a completely new string:
text = "Hello"
old_id = id(text)
text += " World"
print(id(text) == old_id) # Returns False2. Passing Arguments to Functions
Python uses a mechanism called "call-by-object-reference" or "pass-by-assignment."
- When a mutable object is passed to a function, any modifications made directly to that object persist outside the function's scope.
- When an immutable object is passed, changes create a new local object, leaving the original caller's value unchanged.
def modify_data(my_list, my_int):
my_list.append(99) # Modifies original object
my_int += 1 # Rebinds local variable to a new integer
nums = [1, 2]
count = 10
modify_data(nums, count)
print(nums) # Output: [1, 2, 99]
print(count) # Output: 103. Dictionary Keys and Set Elements
Dictionaries and sets rely on hash values to index and look up elements in constant time (\(O(1)\)). Only hashable objects can be used as dictionary keys or set members.
Because an object's hash value must remain constant throughout its
lifetime, only immutable objects can be hashed.
Attempting to use a mutable type, such as a list or a dictionary, as a
dictionary key or set item raises a
TypeError: unhashable type.
The Edge Case: Immutables Containing Mutables
An immutable container can hold references to mutable objects. For
example, a tuple is immutable, but it can contain a
list:
nested_tuple = ([1, 2], "text")
nested_tuple[0].append(3)
print(nested_tuple) # Output: ([1, 2, 3], 'text')The tuple itself cannot have elements added, removed, or reassigned, but the mutable objects it references can still be modified internally.