Skip to main content

Command Palette

Search for a command to run...

Mutable vs Immutable in Python — explained simply (with examples)

Learn the key differences between mutable and immutable objects in Python, with simple examples and common pitfalls.

Published
4 min read
Mutable vs Immutable in Python — explained simply (with examples)

When you learn Python, one small idea keeps coming up in different places: mutable and immutable. It sounds technical, but once you get it, a lot of little bugs start to make sense. This article walks through the concept in plain language, with examples you can copy and try right away.

Why this matters

Understanding mutability helps when you:

  • Debug weird behavior where a value changes unexpectedly.

  • Choose the right data type for keys in a dictionary.

  • Write code that is safe when objects are shared across functions or threads.

Think of it as learning how Python keeps and hands out values. That knowledge makes your code easier to reason about.


What “mutable” and “immutable” mean

  • Immutable: the object cannot be changed after it is created. If you want a different value, Python makes a new object and the variable points to that new object.

  • Mutable: the object can be changed in place. You modify the object itself, and anyone holding a reference to it sees the change.

A quick analogy: immutable objects are sealed envelopes. If you want a different message you must put it in a new envelope. Mutable objects are whiteboards you can erase and rewrite.


Common immutable types

  • int, float, complex

  • str

  • tuple

  • frozenset

  • bytes

Example: integers and strings

a = 100
print(id(a))   # address of object 100

a = a + 50
print(a)       # 150
print(id(a))   # different id: Python created a new int
s = "hello"
print(id(s))

s = s + " world"
print(s)       # "hello world"
print(id(s))   # different id: new string object

When you "change" an immutable, you actually get a new object.


Common mutable types

  • list

  • dict

  • set

  • bytearray

Example: lists

lst = [1, 2, 3]
print(id(lst))

lst.append(4)
print(lst)     # [1, 2, 3, 4]
print(id(lst)) # same id: list changed in place

Because the list object itself was modified, the memory address stays the same.


Why immutability is useful

  1. Hashability and dictionary keys
    Immutable objects can be keys in dictionaries and elements in sets. Mutable objects cannot.

     d = {(1, 2): "tuple works"}
     # d[[1, 2]] = "list doesn't"  # raises TypeError
    
  2. Safer sharing
    If two parts of code need to read the same value and you do not want one part to accidentally change it, use an immutable type.

  3. Predictable behaviour
    With immutable objects, functions that receive them cannot alter the original value. That makes reasoning about your code easier.


When mutability is better

  1. Performance for in-place changes
    If you need to build up or change a collection frequently, a list or dict avoids creating many temporary objects.

  2. Convenience
    Methods like append, extend, pop, and update let you update content directly and express intent clearly.

Example:

cache = {}
def add_value(key, value):
    cache[key] = cache.get(key, 0) + value

Using a mutable dict here is natural and efficient.


Gotchas and common pitfalls

1. Shared references

If you assign a list to another variable, both names point to the same list.

a = [1, 2]
b = a
b.append(3)
print(a)  # [1, 2, 3]  — a changed too

If you want a copy, create one explicitly:

b = a.copy()        # shallow copy for lists
b = a[:]            # slice copy

2. Default mutable arguments

Avoid using mutable objects as default function arguments.

def add_item(x, items=[]):  # bad: same list reused across calls
    items.append(x)
    return items

print(add_item(1))  # [1]
print(add_item(2))  # [1, 2]  unexpected

Safer pattern:

def add_item(x, items=None):
    if items is None:
        items = []
    items.append(x)
    return items

3. Tuples are not always safe

Tuples are immutable, but if a tuple contains a mutable object, that inner object can still change.

t = (1, [2, 3])
t[1].append(4)
print(t)  # (1, [2, 3, 4])  inner list changed

Quick reference table

PropertyMutableImmutable
Change in placeYesNo
Can be dict key / set elementNoYes
Example typeslist, dict, setint, str, tuple

How to decide what to use

  • Use immutable types when you want safety, hashability, and simple reasoning.

  • Use mutable types when you need to update collections often or manage state.

  • When in doubt, prefer immutability for values passed between modules or threads, and use mutability for local, changing data structures.


Short checklist for everyday coding

  • Are you passing this object to other functions that might modify it? If yes, either copy it or use an immutable type.

  • Do you need this as a dictionary key? Use an immutable type.

  • Will the value change often? Use a mutable type for efficiency.


Final note

Mutability is one of those small concepts that reduces a lot of confusion once you internalize it. Next time your variable changes unexpectedly, ask two questions:

  1. Is this object mutable?

  2. Who else holds a reference to it?

That will usually point you to the right fix.