Mutable and Immutable Data Types in python explain using examples

In this article, let us learn about mutable and immutable datatypes in Python and see when to use which one.

If you have been working with Python for a while, whenever you are searching online for some information to solve certain issues, you will frequently come across the terms “mutable” and “immutable”. This article is all about demystifying those terms and making them part of our work vocabulary!

For those of you in a hurry, here is a short infographic explaining each one.

Mutable vs Immutable Datatypes: The Short Version of the Answer

The following cheat sheet summarizes the differences between mutable and immutable data types,

If the table and infographic before it raised more questions than answers, then do not worry as it was meant to be a “quick reference” to people who are already familiar with the topic. The rest of the article is written looking at things from a beginner’s perspective, so let’s start, shall we!

Mutable and Immutable objects, a detailed look

Immutable objects, in simple words, are objects that cannot be changed after you have created them. If you have created an immutable object and then try to change it, an error will be raised as it is not how it is designed to work!

For example, consider the code below.

myString = "qello"
for i in range(5):
    print(myString[i])

myString[0] = 'H'

This will produce the following output.

q
e
l
l
o
Traceback (most recent call last):
  File "main.py", line 5, in <module>
    myString[0] = 'H'
TypeError: 'str' object does not support item assignment

As you can see, while it is possible to read the characters in the string using indices, it is not possible to edit the contents and you end up with an exception!

If you feel nauseous every time you see an exception, I suggest reading our other article on how to read and understand the error texts!

Coming back to the topic, the error text is basically telling us that the string cannot be edited.

Alright, but what if we do this instead

my_word = "first"
print("The value of 'my_word' now is:", my_word)

my_word = "second"
print("The value of 'my_word' now is:", my_word)
The value of 'my_word' now is: first
The value of 'my_word' now is: second

Did we edit the content inside my_word?

Even though it looks like we managed to edit the string, the reality is, if you try to change the value contained inside a string object, a new object will be created in its place and the previous object will no longer be accessible.

The following section shows how to figure out if a given object is mutable or not.

How to determine if a given datatype is Mutable or Immutable?

We can use the in-built id() function to determine if a given object is mutable or immutable.

>>> a = "Hello"
>>> id(a)
139704858663216
>>> a = "Hi"
>>> id(a)
139704858512432

As you can see in the example, in line-1 we have assigned the string “Hello” to variable “a”. After this line is executed, Python will create the string object “Hello” in memory and the variable “a” will refer to this memory location as shown below

In other words, whenever we try to change an immutable object, Python automatically creates a new object with your new value under the same name. After this, you won’t be able to access the old object anymore, since it is not connected to any variable name!

As you can see a brand new string object with the value “Hi” and ID 139704858512432 is created in the memory and the variable “a” is now pointing to this new object.

Even if you do something simple like shown below, the ID will change

>>> a = "Hello"
>>> id(a)
139704859813296
>>> a = a + " World!"
>>> a
'Hello World!'
>>> id(a)
139704858512432

So the point to remember here is

Python does not edit the strings in place and even editing a single letter in a string will result in a brand new string and a change of ID

If you are unclear about what the id() function does, I suggest you read our other article on “is vs ==” where we have explained the concept in more detail!

Integers are another example of immutable objects, which can be shown using the same logic as in the example below.

>>> a = 10
>>> print("The value of a is:", a, "and its id is:", id(a))

The value of a is: 10 and its id is: 9789248
>>> a = 20
>>> print("The value of a is:", a, "and its id is:", id(a))
The value of a is: 20 and its id is: 9789568

Alright, let us see one more example, this time with Lists, and see if lists are mutable or not!

>>> my_list = [1, 2, 3]
>>> print("my_list:", my_list, "id:", id(my_list))
my_list: [1, 2, 3] id: 139756672002240

>>> my_list.append(4)
>>> print("my_list:", my_list, "id:", id(my_list))
my_list: [1, 2, 3, 4] id: 139756672002240

The conclusion is pretty simple and straightforward, if you did any changes to a mutable object such as a list, its id remains the same. This means that we’re still talking about the same object with only a different value.

However, on the other hand, if we try to alter an immutable object, such as a string in this one, we see its object id is changed. This just means that we cannot change an immutable object and if we try to do so, a new object is created with the new value we entered just like how it is shown.

Now let us have another look at the table from above and see if we can understand it better!

The 1st 2 points are hopefully clear.

The list example above can be used to explain point-3 in our table. As you can see our list started with just 3 items, and then it grew into 4 items, which basically means the memory allocated to store our lists is now increased by 33%.

The need for mutable and immutable objects

If you’re wondering why the objects in Python have been divided into these two categories, I applaud your curiosity!

There are good reasons for Python objects to be created this way, let us see which situations require us to use immutable objects and which situations need mutable objects.

Lets start with the question

Why do we need mutable objects?

Immutable objects require more memory as every time an object is created, a new memory is created and allocated for it. Think about the amount of memory and time it will take when we are dealing with a massive data structure!

For example if lists were immutable (they are not) and had 500,000 elements and we wanted to change it, we will have to make a copy of every single element to the new object that will be created, which is inefficient to say the least! 

To avoid this extremely inefficient method, we have mutable lists!

Mutable objects help save memory and processing times

Okay so if mutable objects are so efficient then

Why do we need immutable objects?

We cannot have all the objects being mutable too as immutable objects have their own uses without which we will find ourselves in a hard spot.

Dictionary keys are a good example of a use case where immutability is needed, as we need each key to be “unique”, else the dictionary will loose all its meaning!

Sets are another place where immutability plays an important role, as by definition, a set is a collection of “unique” objects.

If you wish to refresh your memories on Dictionaries and Sets, we have articles on those topics which you can find in the links below.

Python Dictionary: Everything You Need To Know!

Python Sets: Everything you need to know!

In both these datastructures, the “immutability” property helps in generating unique hashes.

A hash is used maps to an object. If we generate a hash using a list, then we add stuff to that list, then the previously generated hash won’t be useful anymore. This is why we keep hash values as unchangeable constant values and this is where immutable objects play a role!

Side Note: What are Hashes?

So what is this “hash” then?

Hash is nothing but a number that an algorithm spits out taking some digital data as input.

What is special about the output number, a.k.a “the hash” is that no matter what the length of the input is, the output is always of fixed length, and the same input always gives out the same output.

Hashes are used everywhere. A good example is sometimes when we download something off the internet, we will get a short text file along with it, containing a hash named SHA or MD5 (SHA and MD5 are nothing but hashing algorithms) which can be used to verify if the file we downloaded is indeed perfect!

They are also used in our filesystems to check the integrity of our files before opening them.

How is hash calculated in python? The ID of a given object is given as input to the hash function to get the hash as shown below.

>>> x = "apple"
>>> hash(x)
-4546430606256924472

Where is “hash” used for in python?
Hash decided the “uniqueness” of an object, which is important in many scenarios while coding in python.

One example that comes straight to mind is “set”.

By definition, A set is a collection of unique objects, so we need a way to know if a given element is already in the set or not.

So for example

>>> set1 = {'1', '2', '3'}
>>> set1.add('4')
>>> set1
{'1', '2', '3', '4'}
>>> set1.add('3')
>>> set1
{'1', '2', '3', '4'}

How does python know not to add 3 again to the set?

Python maintains a table of hashes and it first checks if a given ID is already present in the hash table or not and only adds elements that are not present in the list.

This hash table entry is only added at the moment the element is added to the set, hence we need to make sure that the element cannot be changed once it is created!

For this reason, Python only allows immutable object types to be added to lists!

Let us see what happens if we try to add a List as a set element!

>>> set1.add([1,2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'

As you can see we get a TypeError saying list is an “unhashable type” and hence cannot be added to the set!

If you ever need to have a list of items as a set element, Python provides us with the “tuple” datatype to represent immutable lists!

>>> set1.add((1,2))
>>> set1
{1, 2, (1, 2), 3, 4}

As you can see, now the tuple (1,2) is added to the set without any errors as tuples are immutable!

To summarise

We need Immutable objects when we need objects to hold a quality of uniqueness throughout the execution of the program.

One concept always made me confused and it took me a while to figure it out, so I decided to address it here.

How are tuples immutable?

As you might know, tuple is an immutable collection of elements. A tuple can contain a mutable or an immutable element, from strings and lists to containing another tuple itself.

Now here, even though you cannot change the tuple, i.e add an element, delete an element etc, you can edit an element inside the tuple as long as it’s mutable!

For example:

>>> random_tuple = ("hello world", [7,8,9],)
>>> random_tuple[1].append(10)
>>> random_tuple
('hello world', [7, 8, 9, 10])

But then the content of the tuple has changed/mutated, how is that immutable then?

The reason is that

A tuple holds only the references to the objects and not the objects themselves!

As you can see in the example below, the IDs/references have not changed before and after editing the list.

>>> random_tuple = ("hello world", [7,8,9],)
>>> id(random_tuple[0])
140706819483504
>>> id(random_tuple[1])
140706819450240
>>> random_tuple[1].append(10)
>>> random_tuple
('hello world', [7, 8, 9, 10])
>>> id(random_tuple[0])
140706819483504
>>> id(random_tuple[1])
140706819450240

Hence even though the list object has changed, the reference to the list object has not, hence tuple has not changed!

if you wish to learn more here is an excellent article explaining the concepts of references and objects.

Also, for your next steps in your Python journey, I invite you to watch our YouTube video on ByteArray, a mutable datastructure!

Conclusion

That’s the end and it’s a wrap, dear readers! Congratulations on coming this far, you are one of the few that has the patience and focus to accomplish things!

All the best in your Python journey, and as usual, welcome to the Embeddedinventor fam!

Thanks to Namazi Jamal for his contributions in writing this article!

Photo of author
Editor
Balaji Gunasekaran
Balaji Gunasekaran is a Senior Software Engineer with a Master of Science degree in Mechatronics and a bachelor’s degree in Electrical and Electronics Engineering. He loves to write about tech and has written more than 300 articles. He has also published the book “Cracking the Embedded Software Engineering Interview”. You can follow him on LinkedIn