Сморим следующий пример.
# определим функцию, где корзина покупателя 'basket'
# по умолчанию должна быть пустым списком покупок
def add_fruit(fruit, basket=[]):
# при покупке - корзина пополняется
basket.append(fruit)
return basket
>>> b = add_fruit("banana")
>>> b
# ['banana']
# Внимание! Аргумент `basket` не передается!!!
>>> c = add_fruit("apple")
>>> c
# ['banana', 'apple']
# Да ладно, ведь при инициализации
# в аргументах функции список пустой.
Из примера видно, что функция add_fruit()
вызывается дважды, при чем аргумент basket
(список сделанных покупок) не передается! Конечным результатом является список из двух товаров ['banana', 'apple']
, как это произошло?
Причина такого поведения заключается в том, что когда интерпретатор определяет функцию, он также создает
аргумент по умолчанию. Затем он связывает этот аргумент и созданный объект (ставит ссылку на него в памяти). В примере, Python выделил пустой список и привязал его к аргументу
basket
(корзине покупок).
Другими словами, пустой список создается один раз и аргумент basket
указывает на него в течение всего времени существования функции. Единственное исключение - это когда аргументу basket
передается другой список, но это не изменит значение по умолчанию. Всякий раз, когда вызывается функция снова, без указания basket
, то она будет использовать значение по умолчанию, которое было создано при определении функции.
Чтобы избежать подобного поведения, аргументы по умолчанию должны быть неизменяемыми! В данном конкретном случае, можно аргументу basket
присвоить значение None
и создать пустой список, если basket is None
, в противном случае работать со списком, который передается в функцию.
Смотрим:
def add_fruit(fruit, basket=None):
if basket is None:
basket = []
basket.append(fruit)
return basket
>>> b = add_fruit("banana")
>>> b
# ['banana']
>>> c = add_fruit("apple")
>>> c
# ['apple']
Теперь создается пустой список покупок всякий раз, когда аргумент basket
не передается функции, что исправляет ошибку.