Tuple is immutable in python

Tags:

I find this very interesting. These examples are from fluent python.

In [145]: t = (0, 1, [2, 3])

In [146]: t[2] += [4, 5]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[146], line 1
----> 1 t[2] += [4, 5]

TypeError: 'tuple' object does not support item assignment

In [147]: t
Out[147]: (0, 1, [2, 3, 4, 5])

Likewise…

In [117]: def foo(a, b):
     ...:     a += b
     ...:

In [118]: x = [1, 2]

In [119]: y = [3, 4]

In [120]: foo(x, y)

In [121]: x
Out[121]: [1, 2, 3, 4]

In [122]: z = (1, 2)

In [123]: w = (3, 4)

In [124]: foo(z, w)

In [125]: z
Out[125]: (1, 2)

The reason of these behaviors are easier to understand if we take a look at the methods of tuple.

In [149]: dir((0, 1))
Out[149]:
['__add__',
 '__class__',
 '__class_getitem__',
 '__contains__',
 '__delattr__',
 '__dir__',
 '__doc__',
 '__eq__',
 '__format__',
 '__ge__',
 '__getattribute__',
 '__getitem__',
 '__getnewargs__',
 '__getstate__',
 '__gt__',
 '__hash__',
 '__init__',
 '__init_subclass__',
 '__iter__',
 '__le__',
 '__len__',
 '__lt__',
 '__mul__',
 '__ne__',
 '__new__',
 '__reduce__',
 '__reduce_ex__',
 '__repr__',
 '__rmul__',
 '__setattr__',
 '__sizeof__',
 '__str__',
 '__subclasshook__',
 'count',
 'index']

Whenever += is called for tuple, say, a += b, what’s actually happening is a + b and then a = a + b. So, += doesn’t directly modify a. Instead, it assigns a + b to a.

Similarly t[2] += [4, 5] performs [2, 3] += [4, 5] first (which is ok), and then assign it result to t[2] (which is an error). That’s why we get [2, 3, 4, 5].