To Mutate or not? That is Python's question

Agbaje Ayomide
4 min readMar 22, 2024

Introduction

In the world of Python programming, one of the fundamental questions that every developer must grapple with is mutability and immutability. These two opposing forces, like the yin and yang of the coding world, govern the behaviour and characteristics of objects in Python. Understanding the nuances of mutable and immutable objects is not just a theoretical exercise but a crucial foundation for writing efficient, secure, and maintainable code.

id and type

Before delving into the depths of mutability and immutability, it is essential to understand the concepts of object identity and type in Python. Every object in Python has a unique identity, represented by its memory address, which can be obtained using the id() function. Additionally, each object belongs to a specific type, which defines the set of operations that can be performed on that object and can be determined using the type() function.

a = 10
b = 10
print(id(a), id(b)) # Output: 140714969905600 140714969905600
print(type(a), type(b)) # Output: <class 'int'> <class 'int'>

In the example above, a and b are both integers with the same value, and they share the same identity because Python caches small integers to optimize memory usage.

mutable objects

Mutable objects, as the name suggests, are objects whose value can be changed after creation. These objects are akin to clay sculptures, malleable and ever-changing, allowing you to modify their internal state without creating a new object. Examples of mutable objects in Python include lists, dictionaries, sets, and custom objects defined by classes.

my_list = [1, 2, 3]
print(id(my_list)) # Output: 140714971926720
my_list.append(4)
print(my_list) # Output: [1, 2, 3, 4]
print(id(my_list)) # Output: 140714971926720

In this example, we create a list my_list and append a new element. The identity my_list remains the same, but its value has changed, demonstrating the mutable nature of lists.

immutable objects

Immutable objects, on the other hand, are objects whose value cannot be changed after they are created. These objects are like precious stones, fixed and unchanging, their internal state etched in stone from the moment they come into existence. Examples of immutable objects in Python include numbers (integers, floats, complex numbers), strings, tuples, and frozen sets.

y_string = "Hello"
print(id(my_string)) # Output: 140714971937872
my_string += " World"
print(my_string) # Output: "Hello World"
print(id(my_string)) # Output: 140714971938000

In this example, we create a string my_string and attempt to concatenate it with another string. However, because strings are immutable, a new object is created with the new value and the identity of my_string changes.

why does it matter, and how differently does Python treat mutable and immutable objects

The distinction between mutable and immutable objects is more than just a theoretical curiosity; it has profound implications for how Python operates and how we, as developers, approach our coding tasks.

Immutable objects are generally more efficient and thread-safe because their values cannot be changed, meaning multiple threads can access the same object without causing conflicts. This makes immutable objects ideal for situations where data integrity and concurrency are crucial.

Mutable objects, on the other hand, are sometimes necessary for specific tasks, such as building complex data structures or modifying data in place. However, their mutability also introduces the potential for unintended side effects and race conditions if not handled carefully.

Python treats mutable and immutable objects differently when they are passed as arguments to functions or assigned to variables. This difference in behaviour is a direct consequence of how Python implements object assignment and can have significant implications for the correctness and efficiency of your code.

How arguments are passed to functions, and what does that imply for mutable and immutable objects

In Python, arguments are passed to functions by reference. This means that when you pass an object as an argument to a function, you pass a reference to that object, not a copy of the object itself.

This behaviour is safe for immutable objects because the object's value cannot be changed. However, this behaviour can lead to unexpected results for mutable objects if you modify the object inside the function.

def modify_list(my_list):
my_list.append(4)
print(f"Inside the function: {my_list}")
original_list = [1, 2, 3]
print(f"Before the function: {original_list}")
modify_list(original_list)
print(f"After the function: {original_list}")

This code will output the following:

Before the function: [1, 2, 3]
Inside the function: [1, 2, 3, 4]
After the function: [1, 2, 3, 4]

As you can see, the original_list has been modified by the modify_list function, even though we did not explicitly return a new list from the function.

To avoid this behaviour, you can create a copy of the mutable object before passing it to the function or return a new object from the function instead of modifying the original object.

Conclusion

In Python programming, the question of mutability and immutability is not just a philosophical difficulty; it is a fundamental aspect of the language that shapes how we think about and work with objects. Immutable objects offer the benefits of thread safety, data integrity, and efficiency, while mutable objects provide the flexibility and power to modify data in place.

The key to mastering this duality lies in understanding the nuances of object behaviour and making informed decisions about when to use mutable objects and when to rely on immutable ones. By embracing both strengths, developers can craft elegant, efficient, and secure code that harnesses the full potential of Python's object-oriented paradigm.

So, the next time you ponder the age-old question, "To mutate or not to mutate?" remember that the answer lies not in a binary choice but in a deep understanding of the yin and yang of Python's mutable and immutable objects.

--

--