Mutable and Immutable in Python

Mutable and Immutable in Python

This article explains mutable and immutable in Python.

YouTube Video

Mutable and Immutable in Python

"Mutable" and "immutable" refer to the mutability of an object. Understanding this helps in avoiding unexpected bugs and efficient memory management.

What is Mutable?

Mutable objects can have their internal state changed after creation.

Main Mutable Data Types

  • list
  • dict
  • set
  • User-defined classes (if their attributes can be modified)

Example: Modifying a List

1numbers = [1, 2, 3]
2numbers[0] = 100
3print(numbers)  # [100, 2, 3]

A list is a mutable object, and its elements can be freely modified.

What is Immutable?

Immutable objects cannot be changed once they are created. Attempting to modify them results in the creation of a new object.

Main Immutable Data Types

  • int
  • float
  • str
  • tuple
  • bool
  • frozenset

Example: Modifying a String

1text = "hello"
2# text[0] = "H"  # TypeError: 'str' object does not support item assignment
3
4text = "H" + text[1:]  # Creates a new string
5print(text)  # "Hello"

Strings are immutable, so you cannot modify them partially.

Comparison of Mutable and Immutable

 1# Mutable example
 2a = [1, 2, 3]
 3b = a
 4b[0] = 100
 5print(a)  # [100, 2, 3] -> a is also changed
 6
 7# Immutable example
 8x = 10
 9y = x
10y = 20
11print(x)  # 10 -> x is unchanged

As you can see from this example, mutable objects are shared by reference, so they can affect other variables. On the other hand, immutable objects create new instances upon reassignment, leaving the original value unaffected.

Inspecting Internal Behavior Using id()

In Python, you can use the id() function to check an object’s ID. The object ID is similar to a memory address.

 1# Immutable int behavior
 2a = 10
 3print(id(a))  # e.g., 140715920176592
 4a += 1
 5print(id(a))  # e.g., 140715920176624 -> ID has changed
 6
 7# Mutable list behavior
 8b = [1, 2, 3]
 9print(id(b))  # e.g., 2819127951552
10b.append(4)
11print(id(b))  # Same ID -> only the content has changed

As shown, a new object is created for immutable types, while mutable types are modified in place.

Functions and Caution with Mutable and Immutable Objects

When passing a mutable object to a function, the original data may be modified.

Example: A Function That Modifies a List

1def modify_list(lst):
2    lst.append(100)
3
4my_list = [1, 2, 3]
5modify_list(my_list)
6print(my_list)  # [1, 2, 3, 100]

Example: A Function That Modifies a Number

On the other hand, attempting to modify an immutable object results in a new object being created.

1def modify_number(n):
2    n += 10
3
4my_number = 5
5modify_number(my_number)
6print(my_number)  # 5 -> unchanged

Practical Considerations

Avoid Using Mutable Objects as Default Arguments

 1# Bad example
 2def add_item(item, container=[]):
 3    container.append(item)
 4    return container
 5
 6print(add_item(1))  # [1]
 7print(add_item(2))  # [1, 2] -> unintended behavior
 8
 9# Good example
10def add_item(item, container=None):
11    if container is None:
12        container = []
13    container.append(item)
14    return container
15
16print(add_item(1))  # [1]
17print(add_item(2))  # [2]

Since default arguments are evaluated only once at function definition, using mutable objects can lead to unexpected side effects.

  • In the first example, the same list object is used every time add_item is called. When calling add_item(2) the second time, the previously added 1 is still in the list, resulting in [1, 2].
  • In the improved example, None is used as the default value, and a new list is created inside the function if the argument is None. This ensures that a new list is created each time the function is called, so previous results do not affect subsequent calls.

Avoid using mutable objects like lists or dictionaries as default arguments; instead, use None and initialize them inside the function. This is a fundamental and important best practice in Python.

Summary

To deeply understand Python’s variables and data types, it’s crucial to grasp the differences between mutable and immutable. Understanding these characteristics helps you avoid unintended behavior in your code and write more robust and readable programs.

You can follow along with the above article using Visual Studio Code on our YouTube channel. Please also check out the YouTube channel.

YouTube Video