Изменяемые и неизменяемые типы: list против tuple
Разбираем вопрос, с которого часто начинают Python-секцию интервью: какие типы можно менять «на месте», а какие нет.
Изменяемый (mutable) объект можно менять, не создавая новый: его содержимое правится по тому же адресу в памяти. Неизменяемый (immutable) объект после создания изменить нельзя — любая «правка» создаёт новый объект.
Вопрос: какие типы изменяемые, а какие нет?
Чёткий ответ. Изменяемые: list, dict, set, bytearray. Неизменяемые: int, float, bool, str, tuple, frozenset, bytes, None. Проверить легко: попробуйте изменить элемент.
lst = [1, 2, 3]
lst[0] = 99 # список меняется на месте
print(lst)
t = (1, 2, 3)
try:
t[0] = 99 # кортеж изменить нельзя
except TypeError as e:
print("Ошибка:", e)
Вывод:
[99, 2, 3] Ошибка: 'tuple' object does not support item assignment
Почему это важно: один объект — несколько имён
Имя в Python — это ссылка на объект, а не «коробка со значением». Когда вы пишете b = a, обе переменные указывают на один и тот же объект. Для неизменяемых типов это безопасно, а для изменяемых — источник классических багов: правка через одно имя видна через другое.
a = [1, 2, 3]
b = a # b и a — одно и то же
b.append(4)
print("a:", a) # изменили b — но a тоже изменился
print("a is b:", a is b)
Вывод:
a: [1, 2, 3, 4] a is b: True
С неизменяемыми типами такой ловушки нет: n = 5; m = n; m += 1 не трогает n, потому что m += 1 создаёт новый объект и переназначает имя.
Зачем вообще нужны неизменяемые типы
- Ключи словаря и элементы множества. Они должны быть хешируемыми, а хешируемость требует неизменяемости. Поэтому ключом может быть
tuple, но неlist. - Безопасность. Неизменяемый объект нельзя случайно испортить из чужого кода — его можно свободно передавать и кешировать.
- Скорость и память. Интерпретатор может переиспользовать неизменяемые объекты (например, кешировать малые числа).
d = {(1, 2): "точка"} # tuple как ключ — ок
print(d[(1, 2)])
try:
bad = {[1, 2]: "x"} # list как ключ — нельзя
except TypeError as e:
print("Ошибка:", type(e).__name__)
print("list — нехешируемый тип")
Вывод:
точка Ошибка: TypeError list — нехешируемый тип
Итог
- Изменяемые:
list,dict,set. Неизменяемые: числа,str,tuple,frozenset. - Присваивание копирует ссылку, а не объект — для mutable это создаёт общие данные между именами.
- Ключом словаря и элементом множества может быть только неизменяемый (хешируемый) объект.