datarekha
Python Easy Asked at AmazonAsked at MicrosoftAsked at Google

Which Python built-in types are mutable and which are immutable, and why does it matter?

The short answer

Immutable types — int, float, bool, str, bytes, tuple, frozenset — cannot be changed after creation; operations return new objects. Mutable types — list, dict, set, bytearray — can be changed in place. Mutability determines hashability (only immutables can be dict keys/set members), function side-effect behaviour, and thread-safety considerations.

How to think about it

What the interviewer is checking

This question is a gateway to several deeper topics: “why can’t lists be dict keys?”, “why did my function modify the caller’s list?”, “why does x = x + 1 not mutate x?”. A strong answer covers the table, explains rebinding vs mutation, and demonstrates the function side-effect consequence.

Quick reference

TypeMutableHashableNotes
int, float, boolNoYesSmall ints cached by CPython
strNoYesInterned for many literals
tupleNoYes (if all contents hashable)Shallow immutability
frozensetNoYesImmutable counterpart to set
bytesNoYes
listYesNo
dictYesNoKeys must be hashable
setYesNoElements must be hashable
bytearrayYesNoMutable counterpart to bytes

Mutation vs rebinding — the most common confusion

Reassigning a variable is not mutation. It makes the name point to a different object while the original object is unchanged.

x = 5
x = 6        # rebinding — x now points to int 6; int 5 is unchanged

lst = [1, 2]
lst.append(3)  # mutation — the same list object is modified in place
lst = [1, 2]   # rebinding — lst now points to a new list object

Interactive demo — see mutation and rebinding side by side

The practical consequences

Hashability: Only immutable objects can be dict keys or set members because their hash must stay constant. A list key would let you change the key after insertion, breaking the hash table.

Function side effects: Pass a list to a function and the function can modify it in place; the caller sees the changes. Pass an int or str and the function can only rebind its local name — the caller’s variable is untouched.

frozenset — the immutable set

fs = frozenset({1, 2, 3})
hash(fs)   # works

lookup = {frozenset({1, 2}): "pair", frozenset({3}): "single"}
lookup[frozenset({1, 2})]   # "pair"

Use frozenset when you need a set as a dict key or as an element of another set.

Learn it properly Variables & Types

Keep practising

All Python questions

Explore further

Skip to content