Immutable vs Mutable Data Types in Python | by Lorraine Li | Towards Data Science

By now you may have heard the phrase “everything in Python is an object”. Objects are abstraction for data, and Python has an amazing variety of data structures that you can use to represent data, or combine them to create your own custom data.
A first fundamental distinction that Python makes on data is about whether or not the value of an object changes. If the value can change, the object is called mutable, while if the value cannot change, the object is called immutable.
In this crash course, we will explore:
The difference between mutable and immutable types
Different data types and how to find out whether they are mutable or immutable
It is very important that you understand the distinction between mutable and immutable because it affects the code you write.
Let’s get started!
This crash course is adapted from Next Tech’s Learn Python Programming course that uses a mix of theory and practicals to explore Python and its features, and progresses from beginner to being skilled in Python. It includes an in-browser sandboxed environment with all the necessary software and libraries pre-installed. You can get started for free here!
To get started, it’s important to understand that every object in Python has an ID (or identity), a type, and a value, as shown in the following snippet:
age = 42print(id(age))    # idprint(type(age))  # typeprint(age)        # value[Out:]10966208<class ‘int’>42
Once created, the ID of an object never changes. It is a unique identifier for it, and it is used behind the scenes by Python to retrieve the object when we want to use it.
The type also never changes. The type tells what operations are supported by the object and the possible values that can be assigned to it.
The value can either change or not. If it can, the object is said to be mutable, while when it cannot, the object is said to be immutable.
Let’s take a look at an example:
age = 42print(id(age))print(type(age))print(age)age = 43print(age)print(id(age))[Out:]10966208<class ‘int’>424310966240
Has the value of age changed? Well, no. 42 is an integer number, of the type int, which is immutable. So, what happened is really that on the first line, age is a name that is set to point to an int object, whose value is 42.
When we type age = 43, what happens is that another object is created, of the type int and value 43 (also, the id will be different), and the name age is set to point to it. So, we didn’t change that 42 to 43. We actually just pointed age to a different location.
As you can see from printing id(age) before and after the second object named age was created, they are different.
Now, let’s see the same example using a mutable object.
x = [1, 2, 3]print(x)print(id(x))x.pop()print(x)print(id(x))[Out:][1, 2, 3]139912816421064[1, 2]139912816421064
For this example, we created a list named m that contains 3 integers, 1, 2, and 3. After we change m by “popping” off the last value 3, the ID of m stays the same!
So, objects of type int are immutable and objects of type list are mutable. Now let’s discuss other immutable and mutable data types!
Mutable sequences can be changed after creation. Some of Python’s mutable data types are: lists, byte arrays, sets, and dictionaries.
As you saw earlier, lists are mutable. Here’s another example using the append() method:
a = list(('apple', 'banana', 'clementine'))print(id(a))a.append('dates')print(id(a))[Out:]140372445629448140372445629448
Byte arrays represent the mutable version of bytes objects. They expose most of the usual methods of mutable sequences as well as most of the methods of the bytes type. Items are integers in the range [0, 256).
Let’s see a quick example with the bytearray type to show that it is mutable:
b = bytearray(b'python')print(id(b))b.replace(b'p', b'P')print(id(b))[Out:]139963525979808139963525979808
Python provides two set types, set and frozenset. They are unordered collections of immutable objects.
c = set((‘San Francisco’, ‘Sydney’, ‘Sapporo’))print(id(c))c.pop()print(id(c))[Out:]140494031990344140494031990344
As you can see, sets are indeed mutable. Later, in the Immutable Data Types section, we will see that frozensets are immutable.
d = {    'a': 'alpha',    'b': 'bravo',    'c': 'charlie',    'd': 'delta',    'e': 'echo'}print(id(d))d.update({    'f': 'foxtrot'})print(id(d))[Out:]1400711143194014007111431940
Immutable data types differ from their mutable counterparts in that they can not be changed after creation. Some immutable types include numeric data types, strings, bytes, frozen sets, and tuples.
You have already seen that integers are immutable; similarly, Python’s other built-in numeric data types such as booleans, floats, complex numbers, fractions, and decimals are also immutable!
Textual data in Python is handled with str objects, more commonly known as strings. They are immutable sequences of Unicode code points. Unicode code points can represent a character.
When it comes to storing textual data though, or sending it on the network, you may want to encode it, using an appropriate encoding for the medium you’re using. The result of an encoding produces a bytes object, whose syntax and behavior is similar to that of strings.
Both strings and bytes are immutable, as shown in the following snippet:
# stringe = 'Hello, World!'print(id(e))e = 'Hello, Mars!'print(id(e))[Out:]140595675113648140595675113776# bytesunicode = 'This is üŋíc0de'  # unicode string: code pointsprint(type(unicode))f = unicode.encode('utf-8')  # utf-8 encoded versionprint(type(f))print(id(f))f = b'A bytes object'        # a bytes objectprint(id(f))[Out:]<class 'str'><class 'bytes'>140595675068152140595675461360
In the bytes section, we first defined f as an encoded version of our unicode string. As you can see from print(type(f)) this is a bytes type. We then create another bytes object named f whose value is b'A bytes object'. The two f objects have different IDs, which shows that bytes are immutable.
As discussed in the previous section, frozensets are similar to sets. However, frozenset objects are quite limited in respect of their mutable counterpart since they cannot be changed. Nevertheless, they still prove very effective for membership test, union, intersection, and difference operations, and for performance reasons.
The last immutable sequence type we’re going to see is the tuple. A tuple is a sequence of arbitrary Python objects. In a tuple, items are separated by commas. These, too, are immutable, as shown in the following example:
g = (1, 3, 5)print(id(g))g = (42, )print(id(g))[Out:]139952252343784139952253457184
I hope you enjoyed this crash course on the difference between immutable and mutable objects and how to find out which an object is! Now that you understand this fundamental concept of Python programming, you can now explore the methods you can use for each data type.
If you’d like to learn about this and continue to advance your Python skills, Next Tech has a full Learn Python Programming course that covers:
Functions
Conditional programming
Comprehensions and generators
Decorators, object-oriented programming, and iterators
File data persistence
Testing, including a brief introduction to test-driven development
Exception handling
Profiling and performances
You can get started here for free!