Containers
A container is an object that contains a reference to another object. A common
example would be a List
.
>>> shopping_list = ["milk", "bread", "eggs"]
>>> onions = "onions"
>>> shopping_list.append(onions)
>>> shopping_list
['milk', 'bread', 'eggs', 'onions']
>>> id(onions)
4563363056
>>> id(shopping_list[3])
4563363056
In this example, we are creating a List called shopping_list
and added the
onions
object to it. shopping_list
contains a reference to the onions
variable. We can easily see that by checking the identity of onions
and the
element in the List we have just added.
Mutability
An objects mutability tells us whether or not we can change its value. If it is mutable, we can change it. If it is immutable, we cannot. An object’s mutability comes from its type.
It is important not to get an objects mutability confused with the mutability of a variable. For example:
>>> number = 5
>>> id(number)
4362428304
>>> number += 1
>>> number
6
>>> id(number)
4362428336
In this example, we have the object 5
assigned to the variable number
. We
then increment number
by 1. Number objects in Python are immutable (well, you
can’t change the value of 5 to something else can you?) so what we see here is
that the result of the expression is a new object (in this case the object for
the number 6). This is then assigned to the number
variable. We can see this
in action by looking at the identity of the object behind the number
variable
before and after the expression.
Other common immutable types in Python are strings, bools and tuples.
Mutable Containers
You might be asking what types are mutable. There are two common mutable types. Dictionaries and Lists.
A List is mutable because you can add and remove items. E.g.
>>> shopping_list = []
>>> id(shopping_list)
4456599792
>>> shopping_list.append("milk")
>>> id(shopping_list)
4456599792
In this example, we create the List shopping_list
and add “milk” to it. The
identity behind the shopping_list
variable doesn’t change, so we know that it
is the same object. However, we have changed its value (by adding an element to
the List) so we know it must be mutable.
Immutable Containers
The official documentation on the Python Data Model says:
In most cases, when we talk about the value of a container, we imply the values, not the identities of the contained objects; however, when we talk about the mutability of a container, only the identities of the immediately contained objects are implied. So, if an immutable container (like a tuple) contains a reference to a mutable object, its value changes if that mutable object is changed.
What does this mean? Well, it means several things:
1. The value of a container is typically the combination of the value of the items it contains.
>>> shopping_list = ["milk"]
>>> shopping_list
['milk']
>>> shopping_list.append("bread")
>>> shopping_list
['milk', 'bread']
When we add “bread” to the shopping list, the List’s value changes.
2. A container is immutable if the collection of things it holds cannot change.
>>> shopping_list = ["milk"]
>>> shopping_list.append("bread")
>>> shopping_list
['milk', 'bread']
>>> final_shopping_list = tuple(shopping_list)
>>> final_shopping_list.append("eggs")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'tuple' object has no attribute 'append'
A tuple is immutable, you cannot add additional items to it.
3. Normally, an immutable object’s value cannot change however, when it is a container that holds mutable objects, its value can change.
>>> my_tuple = tuple([5, "hello", ["one"]])
>>> my_tuple
(5, 'hello', ['one'])
>>> my_tuple[0] = 6
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
>>> my_tuple[2].append("two")
>>> my_tuple
(5, 'hello', ['one', 'two'])
A tuple that contains a number, cannot change that number. This is because the number object is immutable, so to have a different number would mean having a different number. Because a tuple is an immutable container, the identities it contains cannot change. So the number cannot change.
However, a List is a mutable type. We can append to the List and change its value, and therefore the tuple’s value. The List is the same object as before, with the same identity, so this is possible.