- en
- Language: ru
- Documentation version: latest
9. Мутация¶
Мутабельный и неизменяемый типы данных в Python вызывают много головной боли у начинающих программистов. Простыми словами, mutable означает «способный к изменению», а immutable - «постоянный». Хотите, чтобы у вас голова пошла кругом? Рассмотрим следующий пример:
foo = ['hi']
print(foo)
# Output: ['hi']
bar = foo
bar += ['bye']
print(foo)
# Output: ['hi', 'bye']
Что только что произошло? Мы этого не ожидали! Мы ожидали чего-то подобного:
foo = ['hi']
print(foo)
# Output: ['hi']
bar = foo
bar += ['bye']
print(foo)
# Expected Output: ['hi']
# Output: ['hi', 'bye']
print(bar)
# Output: ['hi', 'bye']
Это не ошибка. Это мутабельность в действии. Всякий раз, когда вы присваиваете переменную другой переменной с изменяемым типом данных, любые изменения данных отражаются в обеих переменных. Новая переменная - это просто псевдоним старой переменной. Это справедливо только для изменяемых типов данных. Здесь есть одна загвоздка, связанная с функциями и изменяемыми типами данных:
def add_to(num, target=[]):
target.append(num)
return target
add_to(1)
# Output: [1]
add_to(2)
# Output: [1, 2]
add_to(3)
# Output: [1, 2, 3]
Возможно, вы ожидали, что он будет вести себя по-другому. Возможно, вы ожидали, что при вызове add_to
вот так будет создан свежий список:
def add_to(num, target=[]):
target.append(num)
return target
add_to(1)
# Output: [1]
add_to(2)
# Output: [2]
add_to(3)
# Output: [3]
И снова причиной этой боли является изменяемость списков. В Python аргументы по умолчанию оцениваются один раз при определении функции, а не при каждом ее вызове. Вы никогда не должны определять аргументы по умолчанию с изменяемым типом, если не знаете, что делаете. Вы должны сделать что-то вроде этого:
def add_to(element, target=None):
if target is None:
target = []
target.append(element)
return target
Теперь каждый раз, когда вы вызываете функцию без аргумента target
, создается новый список. Например:
add_to(42)
# Output: [42]
add_to(42)
# Output: [42]
add_to(42)
# Output: [42]