Изменяемый аргумент по умолчанию
Изменяемый аргумент по умолчанию (англ. mutable default argument) - распространенная, но легко решаемая проблема при работе с функциями и классами на Python.
В чем проблема?
Представьте себе, что мы написали функцию, которая добавляет к списку значение no_zeros
, если список не содержит числа 0
. Функция отлично работала, но затем мы решили, добавить пустой список по умолчанию:
>>> def no_zeros(lst=[]):
if 0 not in lst:
lst.append('no zeros')
return lst
print(no_zeros([]))
print(no_zeros())
print(no_zeros([0, 1, 2]))
print(no_zeros())
print(no_zeros())
>>> print(no_zeros([]))
... print(no_zeros())
... print(no_zeros([0, 1, 2]))
... print(no_zeros())
... print(no_zeros())
['no zeros']
['no zeros']
[0, 1, 2]
['no zeros', 'no zeros']
['no zeros', 'no zeros', 'no zeros']
Пока мы передаем в функцию список, все работает отлично, но каждый раз, когда мы используем аргумент по умолчанию, в него добавляется 'no zeros'
. А это значит, что мы имеем дело с изменяемым аргументом по умолчанию.
Что случилось?
Когда интерпретатор доходит до нашей функции он создает значение по умолчанию и использует его при вызове функции без соответствующего аргумента. Если это значение изменяется, то в дальнейшем оно используется уже в измененном виде. Неизменяемые типы (кортежи, строки и т.д.) защищены от таких действий, но списки, словари и другие изменяемые типы и классы могут создать проблемы.
Что делать?
Эта проблема решается множеством способов, но стандартным решением является следующее. Значением по умолчанию назначается None
, а в теле функции пишется простая проверка. Если соответствующим аргументом выступает None, то вместо него создается наше изменяемое значение.
1 2 3 4 5 6 |
|
>>> print(no_zeros([]))
... print(no_zeros())
... print(no_zeros([0, 1, 2]))
... print(no_zeros())
... print(no_zeros())
[None]
[None]
[0, 1, 2]
[None]
[None]
В этом случае каждый раз создается новый список. Такое решение является распространенным паттерном, и часто используется в программах на Python, чтобы избежать изменяемых аргументов по умолчанию.
Заключение
Подводя итог, можно с уверенностью сказать, что не стоит использовать изменяемые аргументы по умолчанию без очень, очень веской причины. Вместо этого используйте значение None
по умолчанию, и присваивайте изменяемое значение в теле функции.
Возможно будет интересно
🏆 Hello, world!
Мы вчера запустили новый www.pylot.me. Должны были в следующую среду, но запустили вчера.
Как практиковаться в Python?
Для улучшения качества знаний и повышения уровня программиста, необходим постоянный практикум. Где можно это организовать самостоятельно, и как практиковаться в Python?
Условные конструкции и сопоставление структурных шаблонов
Шпаргалка по условным конструкциям и сопоставлению структурных шаблонов