Mutable and inmutable objects in Python

Andres Aristizabal
4 min readJan 13, 2021

In Python we find an interesting premise: everything is an object. Unlike other programming languages, everything in Python is really an object, including integers, lists, and even functions.

This concept can be confusing for beginning developers, especially if you add the difference between mutable and immutable objects to the mix.

In Python, everything is an object

Although the title of this post deals with mutable and immutable objects in python, it is important, in order to demonstrate these states, to understand how the type() and id() built-ins work.

type() returns the class to which the object belongs and id() returns a unique identifier for the object that has been passed as an argument (this id is actually the memory address of the object), let’s see the following example:

>>> x = 1
>>> id(x)
10105088
>>> type(x)
<class 'int'>

If we analyze this code closely, we find the assignment of a variable x to an object that, as our output clearly indicates, belongs to the int class, this object has an id of 10105088. What would happen if we call id() and type( ) passing the integer 1 as argument? Let’s find out.

>>> type(1)
<class 'int'>
>>> id(1)
10105088
>>>

We find the same output as the previous example, which should make two things very clear:

  1. If integers are objects, then really everything in Python certainly must be an object (we’ll see more examples later).
  2. The variables in Python do not work under the already popular analogy of the box that stores “data”, the variables in python are better understood as references to a certain memory location where the object lives, something similar to a pointer in C.

Other examples of class instances in Python:

>>> def my_function():
... pass
...
>>> type(my_function)
<class 'function'>
>>>
>>> type(1.2)
<class 'float'>
>>>
>>> type(True)
<class 'bool'>
>>>
>>> some_string = "Monty Python"
>>> type(some_string)
<class 'str'>
>>>
<class 'float'>

As you can see, everything in Python is an object … and now that we have demonstrated it, we are going to concentrate on the difference between mutable and immutable objects, a fundamental concept to be able to work properly with the tools that the language provides us.

Immutable objects in Python

For some types in Python, once we have created instances of those types, they never change. They are immutable. We can see this behavior reflected in the following types: int, float, tuple, bool, and str cannot change their content, hence their naming of immutable. let’s see an example:

>>> my_tuple = (1, 2, 3)
>>> id(my_tuple)
139721312996376
>>> my_tuple = (3, 4, 5)
>>> id(my_tuple)
139721273485064

We can see that our assignment actually changed the object that the name my_tuple is bound to.

What happens if we try to change one of the tuple’s elements?

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

As you can see, the program throws an error alerting us that an object of type tuple cannot change its values ​​…

Let’s see what happens when we try to change the value of a string:

>>> some_string[0] = "N"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment

We get the same type of error, as we pointed out earlier, both the tuple and string objects are immutable and therefore their state cannot change.

Mutable objects in Python

Although we pointed out in a previous example that a tuple cannot change because it is immutable, this does not mean that its values ​​cannot change, let’s look at the following example …

>>> mutable_tuple = ([1, 2], 3)
>>> id(mutable_tuple)
139721313021064
>>> mutable_tuple
([1, 2], 3)
>>> mutable_tuple[0][0] = 100
>>> id(mutable_tuple)
139721313021064
>>> mutable_tuple
([100, 2], 3)

Let’s understand what has happened in this example, first, we find a trivial definition of a tuple with an id that has been created for it with the number 139721313021064, next step we reassign the value of the zero index of the list in the zero position of tuple to 100, the tuple id remains the same, this raises several questions.

  1. How is it possible that it remains the same object if its essence is to be immutable?
  2. Why didn’t the interpreter throw an error when trying to make a modification to its content?

The answers to these questions are found in the example itself. Although a tuple is immutable, this does not mean that it cannot hold mutable objects, of which lists is one of them.

If we analyze the output, we observe that the id of the tuple never changed, this is because its content was never modified, the tuple still has a list with its respective identifier “x” and an integer, the only thing that has changed are the list data, object cataloged as mutable.

Let’s finish this example with a last look at the list that we find inside the tuple

>>> mutable_tuple = ([1, 2], 3)
>>> id(mutable_tuple[0])
139721273410504
>>> mutable_tuple[0][0] = 100
>>> id(mutable_tuple[0])
139721273410504

This gives us an important conclusion, mutable objects can change their state as seen in the example, although we reassign the value 100 at index 0 of the list, the latter retains its id, which means that it remains the same object.

Other mutable objects that we can find in Python are of type dict or set. Custom classes are generally mutable. In all these we can reassign their values ​​without necessarily having to generate copies of themselves as happens with immutable objects.

Understanding how Python “sees” objects is a key to becoming a better Python programmer. I hope this post has helped you on your journey to mastering Python.

--

--