Чем изменяемые типы отличаются от неизменяемых? Почему список нельзя сделать ключом словаря?
Неизменяемые (immutable): int, float, str, tuple, frozenset, bytes. Любая «модификация» создаёт новый объект.
Изменяемые (mutable): list, dict, set, bytearray, пользовательские объекты по умолчанию.
s = "abc"
print(id(s))
s += "d" # новый объект, id изменился
lst = [1, 2]
lst.append(3) # тот же объект изменён на местеПочему список не может быть ключом. Ключ словаря должен быть хешируемым: его хеш не должен меняться за время жизни, иначе словарь не найдёт значение в той корзине, куда его положил. У изменяемых контейнеров __hash__ намеренно равен None, поэтому {[1, 2]: "x"} даёт TypeError: unhashable type: 'list'. Решение — превратить в tuple.
Нюанс, который отличает сильного кандидата: кортеж хешируем, только если хешируемо всё его содержимое. hash((1, [2])) тоже упадёт.
Практическое следствие — все переменные в Python это ссылки. Передали список в функцию и изменили — изменения видны снаружи. Отсюда ловушка изменяемого аргумента по умолчанию.
- Что будет с def f(x=[])?
- Как сделать пользовательский класс хешируемым?