DEV Community

Andrey
Andrey

Posted on

Don't use mutable default arguments in Python

What is the mutable objects?

Mutable objects — objects that allow you to modify their contents, such as adding, removing, or changing elements, without creating a new object.

  1. Lists: A list is an ordered, mutable collection of items. You can add, remove, or change elements in a list after it's created. Example: [1, 2, 3]
  2. Dictionaries: A dictionary is an unordered collection of key-value pairs. You can add, remove, or modify key-value pairs after the dictionary is created. Example: {'key1': 'value1', 'key2': 'value2'}
  3. Sets: A set is an unordered collection of unique elements. You can add or remove elements from a set after it's created. Example: {1, 2, 3}
  4. Custom classes or objects created using class definitions in Python are also generally mutable, unless you specifically design them to be immutable. Example: MutableClass('Alice', 20)

For example built-in types like strings, tuples, and frozensets are immutable, meaning that you cannot modify them after they are created. When working with mutable types, it's important to be aware of their behavior, especially when passing them as arguments to functions or using them as default arguments.

Why not to use

Mutable default arguments can lead to unexpected behavior because they are created only once during the function definition, and not every time the function is called. This means that if a mutable object like a list or dictionary is used as a default argument and is modified inside the function, the changes will persist across multiple function calls, potentially affecting the behavior of subsequent calls.

Here's an example with mutable default argument:

def add_item(item, items=[]):
    items.append(item)
    return items

print(add_item(1))  # Output: [1]
print(add_item(2))  # Expected output: [2], Actual output: [1, 2]
print(add_item(3))  # Expected output: [3], Actual output: [1, 2, 3]
Enter fullscreen mode Exit fullscreen mode

As you can see, the items is being shared across multiple function calls, and its contents are accumulating with each call.

To avoid this issue, it's recommended to use None as the default value for mutable arguments and create a new mutable object inside the function if the input is None.

Here's the right version:

def add_item(item, items=None):
    if items is None:
        items = []
    items.append(item)
    return items

print(add_item(1))  # Output: [1]
print(add_item(2))  # Output: [2]
print(add_item(3))  # Output: [3]
Enter fullscreen mode Exit fullscreen mode

A new items is created for each function call, ensuring that the lists are not shared across calls, and the function behaves as expected.

In lieu of a conclusion

Understanding the difference between mutable and immutable objects in Python is crucial for writing efficient, reliable and secure code. As a developer, being aware of the consequences of mutability will help you make informed decisions when choosing appropriate data structures and handling function arguments. It will also help prevent unintended side effects and optimize code in terms of performance and memory management.
I hope this article was useful to you and helps you better understand the concepts of changeability and immutability in Python. If you enjoyed this article and want to receive more content of this nature, please clamp, subscribe and welcome to the Digital Creators Community. Stay tuned for the latest programming tips, best practices, and ideas to help you improve your coding journey.
Happy coding!

Top comments (0)