Связано ли поведение дефолтных параметров в Python только со списками или с другими типами данных тоже
Что проверяют
Понимаете ли вы причину, а не запомнили частный случай со списком. Правильный ответ переводит разговор с типа данных на момент вычисления, и по нему видно, разбирается ли человек в модели объектов Python.
Как отвечать
Нет, не только со списками. Значение по умолчанию вычисляется один раз, когда исполняется строка def, и хранится вместе с функцией. Дальше всё решает изменяемость объекта: любой изменяемый умолчательный аргумент будет общим для всех вызовов.
def add(x, acc=[]):
acc.append(x)
return acc
add(1) # [1]
add(2) # [1, 2]
add.__defaults__ # ([1, 2],)Так же ведут себя словарь, множество, collections.Counter и любой экземпляр вашего класса. Отдельная ловушка это выражения, которые фиксируют момент запуска: def log(ts=datetime.now()) навсегда запоминает время импорта модуля, а открытая в умолчании сессия или соединение живут всё время работы процесса.
Неизменяемые значения безопасны не потому, что копируются, а потому что их нельзя изменить на месте: присваивание внутри функции просто создаёт новую ссылку. Но кортеж со списком внутри снова опасен.
Рабочая идиома одна: маркер None и создание объекта внутри функции. Если None это допустимое значение аргумента, заведите свой маркер через object(). В датаклассах изменяемое умолчание запрещено явно, там нужен field(default_factory=list).
Где спотыкаются
Отвечают, что это известный баг со списками, и останавливаются. Дело не в списке и не в баге: у функции один объект по умолчанию на всё время жизни, и словарь показывает ровно то же самое.
Второе: думают, что вызов в умолчании выполняется при каждом обращении к функции. В долгоживущем процессе такое значение застревает на моменте старта, и ошибка всплывает через сутки в виде неверной даты в записях.
Третье: пишут проверку через ложность аргумента вместо сравнения с None. Пустой список, ноль и пустая строка попадут в ту же ветку, и функция тихо подменит то, что ей передали.