immutability is not strictly the same as having an unchangeable value, it is more subtle

Chris Angelico rosuav at gmail.com
Tue Apr 16 04:11:03 EDT 2019


On Tue, Apr 16, 2019 at 5:44 PM Arup Rakshit <ar at zeit.io> wrote:
>
> Hi,
>
> I am reading a sweet introduction about Python object from [3.1. Objects, values and types](https://docs.python.org/3/reference/datamodel.html#objects-values-and-types). And here the author is said about the Object values nice way:
>
> > The value of some objects can change. Objects whose value can change are said to be mutable; objects whose value is unchangeable once they are created are called immutable. (The value of an immutable container object that contains a reference to a mutable object can change when the latter’s value is changed; however the container is still considered immutable, because the collection of objects it contains cannot be changed. So, immutability is not strictly the same as having an unchangeable value, it is more subtle.) An object’s mutability is determined by its type; for instance, numbers, strings and tuples are immutable, while dictionaries and lists are mutable.
>
> But what I don’t understand here is that what he said about the immutable container objects. Why after changing the value of internal mutable objects we still say the container object as mutable? Any examples to define what the author meant will be helpful.
>

A tuple is immutable.

>>> x = (1, 2, 3)
>>> x[1] = 4
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

This is true even if the tuple contains mutable objects:

>>> x = (1, [], 3)
>>> x[1] = ["test"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

But since those objects are themselves mutable, you can change the
overall value of the tuple:

>>> x = (1, [], 3)
>>> x[1].append("test")
>>> x
(1, ['test'], 3)

Since equality is defined by the values of the tuple's contents, that
means that two equal tuples can become unequal:

>>> y = (1, ["test"], 3)
>>> x == y
True
>>> y[1][0] = "other"
>>> x == y
False

Thus, a tuple that contains mutable objects will always contain the
same objects (defined by *identity*), but may not always represent the
same value (defined by nested values). A tuple that contains any
mutable objects is going to be unhashable, even though tuples in
general are hashable:

>>> stuff = {}
>>> stuff[(1, 2, 3)] = "ok"
>>> stuff[(1, [], 3)] = "not ok"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

Mutability (defined by identity) will usually correspond to
hashability (defined by value), but this is the subtler case that the
author was referring to.

ChrisA


More information about the Python-list mailing list