If you have been learning Python for even a short time, you have probably seen the word immutable in error messages, documentation, or tutorials — and wondered what it really means. This tutorial explains the concept from first principles, with examples you can run and challenges you can try.
Python organizes its values into objects. Every object has a type, a value, and an identity. The word immutable describes what can happen to that value after the object is created. For an immutable object, nothing can. For a mutable object, the value can change while the identity stays the same. Understanding this distinction shapes how you read code, how you track bugs, and how you make decisions about which data structures to reach for.
What Immutable Actually Means
Immutable means cannot be changed after creation. Once Python creates an immutable object and gives it a value, that value is locked. You cannot alter it directly. You can, however, create a new object that holds a different value, and you can point a variable name at that new object.
This is a distinction that trips up many beginners. Reassigning a variable looks like you are changing an object, but you are not. You are simply changing which object the variable name refers to. The original object is untouched.
# x points to the integer object 10
x = 10
print(id(x)) # e.g. 140234567890
# "adding 1" does NOT change the object at id 140234567890
# Python creates a NEW integer object (11) and points x at it
x = x + 1
print(id(x)) # a different id — a different object entirely
The integer 10 that existed on the first line still exists in memory, unchanged. Python just stopped using that object for x.
In Python, a variable name is a label, not a container. When you write x = 10, Python creates an integer object with the value 10 and attaches the label x to it. You can move the label to a different object at any time — that does not affect the object itself.
Contrast this with a mutable type. A list is mutable, meaning you can change its contents while keeping the same object:
my_list = [1, 2, 3]
print(id(my_list)) # e.g. 140234599001
my_list.append(4) # modifies the existing object in place
print(id(my_list)) # SAME id — same object, new content
print(my_list) # [1, 2, 3, 4]
The list object was modified in place. Its identity — the number returned by id() — did not change. That is what mutable means: the value changes, the identity stays the same.
A simple test: if you can change the contents of an object without reassigning the variable that points to it, the object is mutable. If every "change" forces you to create a new object, the original type is immutable.
Build the Python statement that creates a string, then attempts to change its first character (which will raise a TypeError because strings are immutable):
word = 'hello' followed by word[0] = 'H'. The first line assigns the string. The second line attempts to change the character at index 0, which raises a TypeError because strings are immutable. append is a list method and does not belong here.
Which Python Types Are Immutable and Which Are Mutable
Python's built-in types split cleanly into two groups. Knowing which side a type falls on saves you from a category of confusing bugs.
- Mutable or immutable
- Immutable
- What this means in practice
- You cannot change the value of an existing integer. Arithmetic always returns a new integer object. Python also caches small integers (typically -5 to 256) so that variables holding the same small value share one object in memory.
- Mutable or immutable
- Immutable
- What this means in practice
- String methods like
.upper()and.replace()always return a new string. You cannot change a single character using index assignment. Because strings are immutable, they can safely be used as dictionary keys.
- Mutable or immutable
- Immutable
- What this means in practice
- You cannot add, remove, or replace elements in a tuple. If a tuple contains a mutable element such as a list, the list contents can still change — but the tuple's own structure (which objects it holds references to) cannot.
- Mutable or immutable
- Mutable
- What this means in practice
- You can append, remove, sort, and reassign elements freely. The list object keeps the same identity while its contents change. Lists cannot be used as dictionary keys because their hash value would be unstable.
- Mutable or immutable
- Mutable
- What this means in practice
- You can add, update, and delete key-value pairs at any time. The dictionary itself is mutable, which is why only immutable objects (such as strings, integers, and tuples containing only immutable elements) can be used as keys.
- Mutable or immutable
- Mutable
- What this means in practice
- You can add and remove elements from a set after creation. Because sets are mutable, they cannot be nested inside other sets. If you need an immutable set, Python provides
frozensetas a hashable, unchangeable alternative.
The code below tries to update a username string by changing the first character to uppercase. One line contains the bug. Click it, then hit check.
username[0] = "A" with username = "A" + username[1:]. Strings are immutable, so you cannot assign to a character position using index notation. The fix builds a new string by concatenating the uppercase letter with the rest of the original string and rebinds the variable to that new object.
Object Identity and the id() Function
Python assigns every object a unique integer called its identity. You can read this number using id(). Two variables can hold the same value but point to different objects, or they can both point to the exact same object. The is operator tests identity (same object), while == tests equality (same value).
a = 5
b = 5
print(a == b) # True — same value
print(a is b) # True — CPython caches small ints, same object
x = 1000
y = 1000
print(x == y) # True — same value
print(x is y) # False — large ints are not cached, different objects
The cached-integer behavior is an implementation detail of CPython (the standard Python interpreter). Python guarantees that integers from -5 to 256 will reuse the same object, but this is not a language rule — it is a performance optimization. You should use == to compare values and reserve is for cases where you genuinely need to know if two names point to the exact same object.
"An object's identity never changes once it has been created." — Python Language Reference, Data Model
For strings, CPython applies a similar optimization called string interning. Short strings that look like identifiers are often interned, meaning equal strings share one object. Longer strings or strings built at runtime may not be interned, so do not rely on is to compare strings.
# Demonstrating what happens to identity when you "change" a string
name = "python"
print(id(name))
name = name.upper() # .upper() returns a NEW string object
print(id(name)) # different id — the original "python" object is untouched
print(name) # PYTHON
A tuple is immutable, but if it contains a list, the list inside it is still mutable. The tuple cannot be made to hold a different list, but the list itself can gain or lose elements. This is a common source of confusion: immutability refers to the object's own structure, not necessarily the values reachable through it.
inner = [1, 2, 3]
container = (10, inner, "fixed")
# This raises TypeError — you cannot replace an element in a tuple
# container[0] = 99
# But this works — the list inside can still be mutated
inner.append(4)
print(container) # (10, [1, 2, 3, 4], 'fixed')
How to Check Whether a Python Object Is Immutable
When you encounter an unfamiliar type, these three steps let you determine whether it is immutable without consulting the documentation every time.
-
Check the type against known immutable types
Use
isinstance(obj, (int, float, str, bool, bytes, tuple))to test whether an object is one of the standard immutable types. If it returnsTrue, the object is immutable. This is the fastest check for built-in types. -
Use id() before and after a reassignment
Assign a value and store its
id(). Then perform an operation that would modify the value if the type were mutable. If theid()changes afterward, the variable now points to a new object — which confirms the original type is immutable. If the id stays the same, the type is mutable. -
Attempt an in-place modification inside a try block
Wrap an item-assignment attempt in a
try/except TypeErrorblock: tryobj[0] = something. If aTypeErroris raised with a message like "object does not support item assignment," the type is immutable. If the assignment succeeds without error, the object is mutable.
Python Learning Summary Points
- An immutable object's value cannot change after it is created. Python's built-in immutable types are
int,float,bool,complex,str,bytes, andtuple. Mutable types includelist,dict,set, andbytearray. - Reassigning a variable does not mutate the original object. It creates a new object (or reuses an existing one) and redirects the variable label to it. The
id()function reveals this: an immutable "update" always produces a new id, while an in-place mutation on a mutable type keeps the same id. - Only immutable objects can be used as dictionary keys or set elements, because Python needs their hash values to remain stable. If you need an immutable version of a list, use a tuple. If you need an immutable version of a set, use a
frozenset.
Immutability is one of those concepts that pays dividends the longer you work with Python. It explains why string methods always return new values, why you can safely share integer constants between parts of a program, and why passing a list to a function can have side effects while passing an integer cannot. Once the mental model clicks, a whole class of confusing Python behaviors resolves itself.
Frequently Asked Questions
Immutable means the value of an object cannot be changed after it is created. If you try to modify an immutable object, Python creates a new object rather than altering the original.
The built-in immutable types in Python include int, float, bool, complex, str, bytes, and tuple.
The built-in mutable types in Python include list, dict, set, and bytearray. These can be changed in place after creation.
Strings are immutable in Python by design. This allows Python to safely reuse string objects, share them across variables, and use them as dictionary keys. Any operation that appears to change a string actually returns a new string object.
Reassigning a variable does not modify the original object. Python creates a new object with the new value and points the variable name at it. The original object is unchanged and will be garbage collected if nothing else references it.
Object identity is a unique integer that Python assigns to every object, accessible via the id() function. For immutable types, Python may reuse the same object for equal small values, which is why two variables holding the same small integer often share the same id.
Yes. A tuple is immutable in the sense that you cannot add, remove, or replace its elements. However, if one of those elements is itself a mutable object such as a list, the contents of that list can still be changed.
Immutable types offer predictability, safety, and performance benefits. They can be used as dictionary keys, shared between threads without data races, and cached by the interpreter. Mutable types are more flexible but require more care to avoid unintended side effects.