Мутабельность определяет, можно ли изменить объект без смены его идентификатора (адреса в памяти):
Влияние на функции:
Пример:
def f(lst): lst.append(42) data = [] f(data) print(data) # [42] def f2(x): x += 1 n = 1 f2(n) print(n) # 1
"Что выведет следующий код?"
def foo(bar=[]): bar.append(1) return bar print(foo()) print(foo())
Ответ: Выведет:
[1]
[1, 1]
Потому что аргументы функции инициализируются один раз при определении, а не каждый вызов. Списки (и другие мутабельные объекты) в аргументах функции — популярная ловушка.
История
В REST API возвращали список через функцию с дефолтным параметром:
def get_default_items(items=[]): items.append('x') return items
Через несколько вызовов обнаружили, что список растёт, хотя ожидалось получение только одного элемента.
История
В функции планировали "заменить" строку:
def replace_word(word): word.replace('a', 'b') word = 'data' replace_word(word) print(word) # Ожидали 'dbtb', получили 'data'
Методы str не меняют исходную строку, а возвращают новую, но значение возвращаемого результата проигнорировали.
История
Работая с вложенными структурами:
original = [[1, 2], [3, 4]] copy = original[:] copy[0][0] = -1 print(original) # [[-1, 2], [3, 4]]
Использовали неглубокое копирование, считая, что изменили только копию, но вложенные объекты остались общими.