Altcademy - a Forbes magazine logo Best Coding Bootcamp 2023

What is mutable in Python

Understanding Mutability in Python

When you're starting out with programming, you might come across the term "mutable." In the context of Python, mutability refers to the ability of an object to change after it has been created. To understand this concept, let's dive into what objects are and how they can be mutable or immutable.

Objects and Types

In Python, everything is an object. An object is a collection of data (variables) and methods (functions) that act on the data. And each object has a type, which defines what kind of data it can hold and what operations can be performed on it.

For example, when you create a number in Python, you're actually creating an object of type int or float. The same goes for text (strings), lists, dictionaries, and so on. Each of these types can be either mutable or immutable.

Immutable Objects

Immutable objects cannot be changed after they are created. If you try to change an immutable object, what actually happens is that a new object is created instead. Numbers (int, float), strings (str), and tuples (tuple) are examples of immutable types in Python.

Example with Integers

x = 10
print(id(x))  # This prints the unique identifier of the object x

x += 1
print(id(x))  # The identifier is different because a new object was created

In this example, when we increase the value of x by 1, we are not changing the original x object. Instead, Python creates a new integer object with the value of 11, and x now refers to this new object.

Example with Strings

greeting = "Hello"
print(id(greeting))  # Unique identifier of the greeting object

greeting += ", World!"
print(id(greeting))  # A new object is created with the concatenated string

Similarly, when we add ", World!" to the greeting string, we aren't altering the original string. Python creates a new string that contains the combined text and updates the reference to point to this new object.

Mutable Objects

On the other hand, mutable objects can be changed after they are created. Lists (list), dictionaries (dict), and sets (set) are examples of mutable types.

Example with Lists

fruits = ["apple", "banana", "cherry"]
print(id(fruits))  # Prints the unique identifier of the fruits list

fruits.append("date")
print(id(fruits))  # The identifier remains the same because the list is mutable

Here, when we add "date" to the fruits list, we're modifying the original list object. The id() of the object remains the same, which indicates that the list has been changed in place.

Why Does Mutability Matter?

Understanding mutability is crucial because it affects how you work with objects in your code. Since immutable objects cannot be changed, they are safe to be used as keys in dictionaries or elements in sets. Mutable objects, however, cannot be used in the same way because their values can change, which would affect their identity.

Mutability in Action

Let's look at an example that demonstrates mutability with a list and immutability with a tuple.

# Mutable list example
my_list = [1, 2, 3]
my_list[0] = 10
print(my_list)  # Output: [10, 2, 3]

# Immutable tuple example
my_tuple = (1, 2, 3)
my_tuple[0] = 10  # This will raise a TypeError

In the my_list example, we can change the first element because lists are mutable. However, attempting to change an element of the tuple my_tuple results in a TypeError because tuples are immutable.

Copying Objects

Understanding mutability also becomes important when you want to make copies of objects.

Shallow Copy

With mutable objects like lists, a shallow copy creates a new list object, but the elements inside are the same objects (references to the objects are copied).

original = [1, 2, [3, 4]]
copy = original.copy()  # Shallow copy

copy[2].append(5)
print(original)  # Output: [1, 2, [3, 4, 5]]

Even though we modified copy, the change also appeared in original because the inner list [3, 4] is the same object in both original and copy.

Deep Copy

A deep copy, on the other hand, creates a new list and recursively adds copies of the objects found in the original.

import copy

original = [1, 2, [3, 4]]
deep_copy = copy.deepcopy(original)  # Deep copy

deep_copy[2].append(5)
print(original)  # Output: [1, 2, [3, 4]]

Here, modifying deep_copy does not affect original because the inner list is a separate object.

Intuitions and Analogies

To help understand mutability, think of a mutable object like a whiteboard. You can write on it, erase it, and modify it without needing a new whiteboard. An immutable object, however, is like a printed page: if you want to change the text, you have to print a new page.

Conclusion: Embrace the Change (or Lack Thereof)

In the world of Python, being mutable is like being flexible, able to adapt and change. Immutable objects, with their steadfastness, provide a sense of reliability and consistency. As you journey through Python, you'll learn when to rely on the unchanging nature of a str or tuple, and when to embrace the dynamic capabilities of a list or dict. Understanding these concepts is like having a map in the ever-changing landscape of programming—knowing the terrain helps you navigate it with confidence and ease. So whether you're modifying elements in a list or keeping your keys constant in a dictionary, remember that the nature of your objects—mutable or immutable—will guide your path to writing effective Python code.