В чем проблема использования изменяемых типов в качестве значений по умолчанию для аргументов функции в Python

Ответ

Проблема в том, что объект, используемый в качестве значения по умолчанию, создаётся только один раз — в момент определения функции, а не при каждом её вызове.

Если этот объект является изменяемым (например, list или dict), то все вызовы функции, которые не передают свой собственный аргумент, будут работать с одним и тем же экземпляром объекта, что приводит к неожиданным побочным эффектам.

Неправильный подход (демонстрация проблемы):

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

# Первый вызов, всё выглядит нормально
list1 = add_item("apple")
print(list1)  # Вывод: ['apple']

# Второй вызов изменяет тот же самый список
list2 = add_item("banana")
print(list2)  # Неожиданный вывод: ['apple', 'banana']

Правильный подход (идиома с None):

Для безопасной работы следует использовать None в качестве значения по умолчанию и создавать новый изменяемый объект внутри функции.

def add_item(item, items_list=None):
    # Если список не передан, создаём новый
    if items_list is None:
        items_list = []
    items_list.append(item)
    return items_list

# Первый вызов
list1 = add_item("apple")
print(list1)  # Вывод: ['apple']

# Второй вызов работает с новым, независимым списком
list2 = add_item("banana")
print(list2)  # Ожидаемый вывод: ['banana']