Immutability in Python

What is exactly immutability?

Tuples are immutable. It means we cannot change the size and/or reassign another element to a given cell.

A = (1, 2, [42])
A[1] = 56
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In[1], line 2
      1 A = (1, 2, [42])
----> 2 A[1] = 56


TypeError: 'tuple' object does not support item assignment

However, if some element at some cell in a tuple is mutable, we can modify it.

L = [42]
A = (1, 2, L)
A[2].append(3)
print(L)
[42, 3]

Use in dictionnaries and sets

When a whole object is immutable (e.g. tuples of integers, tuples of tuples, etc. but not tuples of lists), it can be used as a key in dictionnaries, or an element in sets. This is because they are hashable.

Technical remark. Actually, some mutable objects could be hashable in principle. But it is a terrible idea. Indeed, the hash of such an element could be just defined in terms of the id (address of the pointer) while equality may be defined from the inner values that may change.

S = {1, 2, 3}
S
{1, 2, 3}
S = {"Bonjour", 1}
S = {(1, 2), (3, 0)}
(132).__hash__()
132
(13200000).__hash__()
13200000
(1320000000000000000000).__hash__()
1057798729767060028
(132,).__hash__()
-2719358537048335948
((1, 2)).__hash__()
-3550055125485641917
[1, 2].__hash__()
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In[21], line 1
----> 1 [1, 2].__hash__()


TypeError: 'NoneType' object is not callable
S = {(1, 2), (3, 0), (1, 2)}
S
{(1, 2), (3, 0)}
{[], [1]}
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In[2], line 1
----> 1 {[], [1]}


TypeError: unhashable type: 'list'
([]).__hash__()
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

Cell In[9], line 1
----> 1 ([]).__hash__()


TypeError: 'NoneType' object is not callable
D = {}
type(D)
dict
D = {(1, 2): 3, (5, 67): None}
D[(1, 2)]
3

Creation of a new object or not?

When a type is mutable, Python creates new objects, because we never know... you may modify it later on:

A = [1, 2]
A is A[:]
False

When the type is immutable, Python does not create a new object if not necessary.

A = (1, 2)
A is A[:]
True