LambdaLabTM
Computer Science · Class 11 · Data Types
Data TypesClassification⏱️ 8 min read

Mutable & Immutable

The family tree sorted values by what kind they are. There is a second way to sort exactly the same values, and it asks a different question: once a value has been made, can it be changed? Some can. Most cannot. Python is strict about it, and it will tell you so in plain words.

1The whole idea in one question

Mutable means “can be changed”. Immutable means “cannot be changed”. (The im- at the front flips the meaning, exactly like possible and impossible.)

Careful, though — changed means something precise here. It means changed in place: the value that already exists is edited, and it is still the same value afterwards, just different. It does not mean making a new value that looks similar.

Immutable — like ink

Once it is written, it is written. You cannot rub out one letter. If you want it different, you write a fresh copy on a fresh page — the original is untouched.

Mutable — like a whiteboard

Rub out one word, write another, and it is the same board. The thing itself changed. Nothing new was made.

2Do not take my word for it — ask Python

Here is a fair test, and you already have the tool for it. In the last lesson you learnt indexing[0] reaches the first item of any sequence. So far you have only used it to read an item. Now try to write to it:

immutable.py
word = 'hello'

print(word[0])   # reading position 0 — always fine
word[0] = 'H'    # writing to position 0 — is it allowed?
Output
h
Traceback (most recent call last):
  File "immutable.py", line 4, in <module>
    word[0] = 'H'    # writing to position 0 — is it allowed?
    ~~~~^^^
TypeError: 'str' object does not support item assignment

That is the experiment. Store a value in a variable, send it the same instruction — change the item at position 0 — and watch who obeys and who refuses. Three types can be indexed, so three types can be asked: str, tuple and list.

Pick a value, then try to change one item of it
try_string.py# try to change the first letter of the name to a capital R
1name = 'ramesh'
2name[0] = 'R'← the attempted change
3print(name)
What Python printed
Traceback (most recent call last):
  File "try_string.py", line 2, in <module>
    name[0] = 'R'
    ~~~~^^^
TypeError: 'str' object does not support item assignment
str🔒 Immutable — cannot be changed

A string cannot be edited in place. Position 0 exists — reading name[0] would have given 'r' quite happily — but writing to it is refused. To get 'Ramesh' you must build a brand new string; the old one is never touched.

Three values, one instruction, two different answers — discovered rather than memorised. Compare the tuple program with the list program closely: the only difference in the whole file is ( against [. The tuple refused. The list did not even blink.

Note
Reading that error. 'str' object does not support item assignment sounds frightening and says something very simple: a string will not let you assign a new item into it. It is Python telling you, politely, that strings are immutable.

3The two lists

Here is the classification in full. The good news is that you do not have to memorise both columns — there are only three mutable types in the whole language. Learn those three, and everything else is immutable by default.

🔒 Immutable — cannot be changed
int42
float3.75
boolTrue
complex3 + 7j
str'hello'
tuple(10, 20, 30)
NoneTypeNone
🔓 Mutable — can be changed
list[10, 20, 30]
dict{'name': 'Ramesh', 'marks': 87}
set{10, 5, -2}
Only three. Learn this short column and the long one takes care of itself. You have met the list already; dict is the very next lesson and set comes later, but they belong in the column now so the picture is complete.
Key Takeaway
Numbers, booleans, strings, tuples and None are immutable. Lists, dictionaries and sets are mutable. Notice the neat pair inside the Sequential family: a list can be changed, a tuple cannot. That is the main reason both exist.

4“But I have seen a string change!”

This is the point where everybody objects, so let us settle it. There are two programs that look exactly like a string changing. Neither of them changes a string.

1. A method hands back a new string

unchanged.py
word = 'hello'

print(word.upper())   # a new string comes back
print(word)           # the original never changed
Output
HELLO
hello

Did 'hello' change into 'HELLO'? It did not. upper() built a brand new string and handed it back. The original 'hello' is still 'hello', exactly as it was, untouched somewhere in memory.

2. The same name is given a new value

This one is far more convincing, because one name really does print two different things:

rebind.py
s = "hello"
print(s)

s = "bye"
print(s)
Output
hello
bye

So the string changed? No. Nothing was written into the hello box at all. The line s = "bye" is two separate events, and neither of them edits a string:

first
A new box is reserved

"bye" is a brand new string, so Python reserves a fresh piece of memory for it and puts bye in there. It is not written on top of hello.

then
The label is moved onto it

A name can point at only one box at a time. So the label s is peeled off the hello box and stuck on the new one. s now leads somewhere else.

This is the memory wall from the assignment lesson, and it is the honest picture. Run it line by line and keep your eye on where the label s is:

s = "hello"
print(s)
s = "bye"
print(s)
Screen
Memory (RAM)
Press Run line 1 and watch the memory wall on the right. Nothing exists there yet — the boxes only appear when an = runs.

The word hello is still sitting in memory at the end, letter for letter. Nothing rubbed it out and nothing edited it — it has lost its label, that is all, so no line of your program can reach it any more. (Python tidies away values nothing can reach. Tidying away is not editing.)

And none of this is about strings. Swap in a number and the picture does not change at all — n = 5 then n = 7 gives 7 a box of its own and moves the label n onto it, because the number five cannot become seven. Try the integer and float tabs above and watch the same thing happen. Reassignment works this way for every immutable type.

Key Takeaway
Two different actions, and only one of them is a change. s[0] = 'H' asks Python to edit the value that s points at — that is mutation, and a string refuses it. s = "bye" does not touch that value at all; it points the name at a different value — that is reassignment, and it is allowed for every type in Python. An immutable value can never be mutated. Its name can always be reassigned.
Watch Out
The line that catches people out. Immutable does not mean “you can never get a changed version”. It means the original is never edited. You always get a new value, and the old one carries on being what it always was.

One more thing follows from all of this, and it is the whole of the next lesson. If a name is only a label, then two labels can sit on one value. Whether that is handy or dangerous depends on exactly what you have just learnt — whether the value can be changed.

5Why does any of this matter?

Safety

Some data should not be editable — a date of birth, a set of exam marks already submitted. Put it in a tuple and Python guards it for you.

Convenience

Some data must be edited all the time — a list of students in a class. Put that in a list, and change it as often as you like.

Marks

"Which of these is immutable?" is one of the most common one-mark questions in the paper. It is free marks, if you know the short column.

Try the refusals yourself. Python is very clear about them:

Python prompt — interactive mode
# Try to change a value. See who says no.
>>>
try

6Recap

Key Takeaway
Mutable = can be changed in place. Immutable = cannot. Only three types are mutable: list, dict, set. Everything else — int, float, bool, complex, str, tuple, None — is immutable. A method like upper() does not change a string; it returns a new one. And giving a name a new value — s = "bye" — does not change the old value either: the new value gets its own box and the name is moved onto it.
Quick Check

Which of these is mutable?

Quick Check

After name = 'ramesh', why does name[0] = 'R' give a TypeError?

Quick Check

After word = 'hello' and print(word.upper()), what is inside word?

Quick Check

A program runs s = "hello" and then s = "bye". What happened to the string hello?

Quick Check

Why is n = 5 followed by n = 7 not an example of a value being changed?