От недавнего, ТАКИМ ОБРАЗОМ, вопрос (см., Создает словарь в Python, который индексируется списками), я понял, что у меня, вероятно, была неправильная концепция значения hashable и неизменных объектов в Python.
Хеширование - это процесс преобразования некоторого большого количества данных в гораздо меньший объем (обычно одно целое число) повторяемым способом, чтобы его можно было найти в таблице в постоянном времени ( O (1)
), что важно для высокопроизводительных алгоритмов и структур данных.
Неизменяемость - это идея, что объект не будет изменяться каким-либо важным образом после того, как он был создан, особенно каким-либо образом, который может изменить хеш-значение этого объекта.
Эти две идеи связаны, потому что объекты, которые используются в качестве ключей хеширования, обычно должны быть неизменяемыми, чтобы их хеш-значение не изменялось. Если бы было разрешено изменить, то местоположение этого объекта в структуре данных, такой как хеш-таблица, изменилось бы, и тогда вся цель хеширования для эффективности потерпела бы поражение.
Чтобы по-настоящему понять идею, вам следует попробовать реализовать свою собственную хеш-таблицу на таком языке, как C / C ++, или прочитать Java-реализацию класса HashMap
.
Технически хеширование означает, что класс определяет __ hash __ ()
. Согласно документации:
__ hash __ ()
должен возвращать целое число. Единственное обязательное свойство - это то, что сравниваемые одинаковые объекты имеют одинаковое хеш-значение; рекомендуется как-то смешивать (например, с использованием исключающего ИЛИ) хеш-значения для компонентов объекта, которые также играют роль в сравнении объектов.
Я думаю, что для встроенных типов Python все хешируемые типы также неизменяемы.
Было бы сложно, но возможно, возможно, иметь изменяемый объект, который, тем не менее, определял бы __ hash __ ()
.
Из Глоссария Python :
Объект является хешируемым если у него есть хеш-значение, которое никогда не меняется в течение его времени существования (ему нужен метод
__ hash __ ()
), и его можно сравнивать с другими объектами (ему нужен__ eq __ ()
или__ cmp __ ()
метод). Хэшируемые объекты, которые сравнивают равные, должны иметь одинаковое хеш-значение.Hashability делает объект пригодным для использования в качестве ключа словаря и члена набора, потому что эти структуры данных используют хеш-значение внутри.
Все неизменяемые встроенные объекты Python являются хешируемыми, а изменяемые контейнеры (например, списки или словари) - нет. Объекты, которые являются экземплярами пользовательских классов, по умолчанию хешируются; все они сравниваются неравно, и их хеш-значение - это их id ().
Словари и наборы должны использовать хэш для эффективного поиска в хеш-таблице; значения хэша должны быть неизменными, потому что изменение хэша испортит структуры данных и приведет к сбою dict или set. Самый простой способ сделать хеш-значение неизменяемым - сделать неизменным весь объект, поэтому они часто упоминаются вместе.
Хотя ни один из встроенных изменяемых объектов не является хешируемым, можно сделать изменяемый объект с хеш-значением, не изменяемым. Обычно только часть объекта представляет его личность, тогда как остальная часть объекта содержит свойства, которые можно изменять.Если хэш-значение и функции сравнения основаны на идентификаторе, но не на изменяемых свойствах, и идентификатор никогда не меняется, вы выполнили все требования.
Hashable означает, что значение переменной может быть представлено (или, скорее, закодировано) константой - строка, число и т. д. То, что может быть изменено (изменяемое), не может быть представлено чем-то, чего нет. Следовательно, любая изменяемая переменная не может быть хэшируемой, и, по тому же признаку, хешируемыми могут быть только неизменяемые переменные.
Надеюсь, это поможет ...
В Python они в основном взаимозаменяемы; поскольку хэш должен представлять содержимое, он так же изменчив, как и объект, и если объект изменит хэш-значение, это сделает его непригодным для использования в качестве ключа dict.
В других языках хэш-значение больше связано с "идентичностью" объекта, а не (обязательно) с его значением. Таким образом, для изменяемого объекта указатель может быть использован для начала хэширования. Предполагая, конечно, что объект не перемещается в памяти (как это делают некоторые GC). Такой подход используется, например, в Lua. Это позволяет использовать изменяемый объект в качестве ключа таблицы, но создает несколько (неприятных) сюрпризов для новичков.
В конце концов, наличие неизменяемого типа последовательности (кортежей) делает его более удобным для "многозначных ключей".