Ответ
Нет, хеш объекта (значение, возвращаемое методом __hash__) должен оставаться постоянным на протяжении всего времени его жизни. Это критически важное правило для корректной работы хеш-таблиц, лежащих в основе словарей (dict), множеств (set) и frozenset. Если хеш изменится после помещения объекта в такую коллекцию, он станет недостижим.
Почему это важно: При вставке объекта Python вычисляет его хеш и использует его для определения «корзины» (bucket). При последующем поиске по тому же объекту вычисляется новый хеш. Если он отличается, поиск будет вестись в другой корзине, и объект не будет найден, хотя физически он там есть.
Пример проблемного класса:
class MutableHash:
def __init__(self, name):
self.name = name # Используем атрибут для хеширования
def __hash__(self):
return hash(self.name)
def __eq__(self, other):
return isinstance(other, MutableHash) and self.name == other.name
obj = MutableHash('Alice')
my_set = {obj}
print(obj in my_set) # True
obj.name = 'Bob' # Меняем атрибут, от которого зависит хеш!
print(obj in my_set) # False! Объект «потерялся»
print(hash(MutableHash('Alice'))) # Старый хеш
print(hash(obj)) # Новый хеш. Они не совпадают.
Правила:
- Неизменяемые встроенные типы (
int,str,tuple) имеют постоянный хеш. - Изменяемые типы (
list,dict,set) нехэшируемы (у них нет__hash__). - Пользовательские классы по умолчанию хэшируемы по
id(), но если вы переопределяете__eq__, следует также переопределить__hash__, основывая его на неизменяемых атрибутах.