Ответ
Неизменяемость (immutability) и хэшируемость (hashability) — это разные, но часто связанные свойства объектов в Python.
- Неизменяемый объект — это объект, состояние которого нельзя изменить после создания. При любой "операции изменения" создается новый объект. Примеры:
int,float,str,tuple,frozenset. - Хэшируемый объект — это объект, который имеет хэш-значение (целое число), неизменяемое на протяжении его жизни, и может корректно сравниваться с другими объектами (имеет метод
__eq__). Хэшируемые объекты могут быть ключами в словарях (dict) и элементами множеств (set).
Ключевая связь и различие:
- Почти все встроенные неизменяемые типы хэшируемы.
- Изменяемые типы (списки
list, словариdict, множестваset) — нехэшируемы. - Хэшируемость не гарантирует неизменяемость. Можно создать пользовательский изменяемый класс и определить для него метод
__hash__, но это считается антипаттерном, так как изменение объекта после помещения в словарь нарушит структуру данных.
Примеры:
# 1. Неизменяемый и хэшируемый объект (строка)
my_string = "hello"
my_dict = {my_string: "value"} # Допустимо, строка хэшируема
print(hash(my_string)) # Выведет хэш-значение
# 2. Изменяемый и нехэшируемый объект (список)
my_list = [1, 2, 3]
try:
my_dict = {my_list: "value"} # Вызовет TypeError
except TypeError as e:
print(e) # unhashable type: 'list'
# 3. Кортеж (tuple) хэшируем, только если все его элементы хэшируемы.
tuple_hashable = (1, "two", 3.0)
print(hash(tuple_hashable)) # Работает
tuple_unhashable = (1, [2, 3]) # Содержит изменяемый список
try:
hash(tuple_unhashable) # Вызовет TypeError
except TypeError as e:
print(e) # unhashable type: 'list'
Для тестирования важно понимать эти различия, например, при использовании фикстур pytest или данных в параметризованных тестах, где в качестве ключей параметризации могут использоваться только хэшируемые значения.