Every object in Python is either mutable (can be changed in place) or immutable (cannot be changed — any “modification” creates a new object). This distinction affects how variables behave, especially when we pass them to functions.
Which Types Are Which?
- Immutable —
int,float,str,tuple,frozenset,bool,None - Mutable —
list,dict,set, custom objects (by default)
x
→
"hello" id: 100
x
→
"hello world" id: 200 (NEW)
nums
→
[1, 2, 3] id: 300
nums
→
[1, 2, 3, 4] id: 300 (SAME)
Seeing It in Action with id()
The id() function returns the memory address of an object. We can use it to prove whether an object changed in place or a new one was created.
# Immutable — new object every time
name = "hello"
print(id(name)) # e.g., 140234567890
name += " world"
print(id(name)) # different id — new object was created
# Mutable — same object modified
fruits = ["apple", "banana"]
print(id(fruits)) # e.g., 140234569120
fruits.append("cherry")
print(id(fruits)) # same id — object was modified in place
Why This Matters for Functions
When we pass a mutable object to a function, the function gets a reference to the same object. Changes inside the function affect the original.
def add_item(lst):
lst.append("new") # modifies the original list
my_list = [1, 2, 3]
add_item(my_list)
print(my_list) # [1, 2, 3, 'new'] — original was changed!
With immutable objects, the function can’t change the original — it can only create a new object locally.
def try_change(text):
text += " world" # creates a new string locally
print(text) # "hello world"
msg = "hello"
try_change(msg)
print(msg) # "hello" — original unchanged
In simple language, think of mutable objects like a whiteboard — we can erase and rewrite on the same board. Immutable objects are like printed paper — to change anything, we need a whole new sheet.