Hashable, неизменный
из недавнего вопроса SO (см. Создание словаря в python, который индексируется списками) я понял, что у меня, вероятно, было неправильное представление о значении хэшируемых и неизменяемых объектов в python.
- что означает hashable на практике?
- какова связь между hashable и immmutable?
- есть изменяемые объекты, которые hashable или неизменяемые объекты, которые не hashable?
9 ответов:
хеширования - это процесс преобразования некоторого большого количества данных в гораздо меньшее количество (обычно одно целое число) повторяемым образом, чтобы его можно было искать в таблице в постоянном времени (
O(1)), Что важно для высокопроизводительных алгоритмов и структур данных.неизменность это идея, что объект не будет меняться каким-то важным образом после его создания, особенно в любом случае, что может изменить значение хэша этого объекта.
эти две идеи связаны, потому что объекты, которые используются в качестве хэш-ключей, обычно должны быть неизменяемыми, чтобы их хэш-значение не менялось. Если бы это было разрешено изменить, то расположение этого объекта в структуре данных, такой как хэш-таблица, изменилось бы, а затем вся цель хэширования для эффективности была бы побеждена.
чтобы действительно понять идею, вы должны попытаться реализовать свою собственную хэш-таблицу на языке, таком как C/C++, или прочитать реализацию Java элемент
HashMapкласса.
технически, hashable означает, что класс определяет __hash__(). Согласно документам:
_ _ hash__ () должно возвращать целое число. Единственное необходимое свойство-это то, что объекты, которые сравниваются равными, имеют одинаковое хэш-значение; рекомендуется каким-то образом смешивать (например, используя exclusive или) хэш-значения для компонентов объекта, которые также играют роль в сравнении объектов.
Я думаю, что для встроенных типов python все типы хеширования также неизменны. Было бы трудно, но, возможно, не невозможно иметь изменяемый объект, который тем не менее определял __hash__().
- есть изменяемые объекты, которые hashable или неизменяемые объекты, которые не hashable?
в Python Кортеж является неизменяемым, но он хэшируется только в том случае, если все его элементы хэшируются.
>>> tt = (1, 2, (30, 40)) >>> hash(tt) 8027212646858338501 >>> tl = (1, 2, [30, 40]) >>> hash(tl) TypeError: unhashable type: 'list'Типы Hashable
- атомарные неизменяемые типы все хэшируемые, такие как str, байты, числовые типы
- замороженный набор всегда hashable(его элементы должны быть hashable по определению)
- A кортеж хэшируется только в том случае, если все его элементы хэшируются
- пользовательские типы хэшируются по умолчанию, потому что их хэш-значение-это их id()
объект хэшируется, если он имеет хэш-значение, которое никогда не меняется в течение его жизни (он нуждается в
__hash__()метод), и может быть по сравнению с другими объектами (он нуждается в__eq__()или__cmp__()метод). Хэшируемые объекты, которые сравниваются равными, должны иметь одинаковое хэш-значение.Hashability делает объект пригодным для использования в качестве ключа словаря и элемента набора, поскольку эти структуры данных используют значение хэша внутренне.
все неизменяемые встроенный Python объектов hashable, а не изменяемые контейнеры (такие как списки или словари) являются. Объекты, которые являются экземплярами пользовательских классов, по умолчанию хэшируются; все они сравниваются неравными, и их хэш-значение является их id().
Dicts и наборы должны использовать хэш для эффективного поиска в хэш-таблице; хэш-значения должны быть неизменяемыми, потому что изменение хэша испортит структуры данных и вызовет дикт или установить на провал. Самый простой способ сделать хэш-значение неизменяемым - это сделать весь объект неизменяемым, поэтому они часто упоминаются вместе.
пока ни один из встроенных изменяемых объектов hashable, это можно сделать изменяемый объект с хэш-значение не mutable. Обычно только часть объекта представляет его идентичность, в то время как остальная часть объекта содержит свойства, которые могут быть изменены. Пока хэш функции value и comparison основаны на идентификаторе, но не на изменяемых свойствах, и идентификатор никогда не изменяется, вы выполнили требования.
существует неявный, даже если нет явной связи между принудительным неизменяемые и hashable из-за взаимодействия между
- Хэшируемые объекты, которые сравниваются равными, должны иметь одинаковое хэш-значение
- объект хэшируется, если он имеет хэш-значение, которое никогда не изменяется в течение его жизни.
здесь нет проблем, если вы не переопределите
__eq__таким образом класс объектов определяет эквивалентность по стоимости.один раз вы сделали это, вам нужно найти стабильную хэш-функцию, которая всегда возвращает одно и то же значение для объектов, которые представляют одно и то же значение (например, где
__eq__) возвращает True и никогда не изменяется в течение всего времени существования объекта.трудно увидеть приложение, где это возможно, рассмотрим возможный класс A, который соответствует этим требованиям. Хотя есть очевидный вырожденный случай, когда
__hash__возвращает a постоянный.сейчас:-
>>> a = A(1) >>> b = A(1) >>> c = A(2) >>> a == b True >>> a == c False >>> hash(a) == hash(b) True >>> a.set_value(c) >>> a == c True >>> assert(hash(a) == hash(c)) # Because a == c => hash(a) == hash(c) >>> assert(hash(a) == hash(b)) # Because hash(a) and hash(b) have compared equal before and the result must stay static over the objects lifetime.на самом деле это означает, что при создании hash(b) == hash(c), несмотря на то, что никогда не сравниваются равные. Я изо всех сил пытаюсь увидеть в любом случае, чтобы с пользой определить
__hash__() для изменяемого объекта, который определяет сравнение по значению.Примечание:
__lt__,__le__,__gt__и__ge__сравнения не затрагиваются, поэтому вы все равно можете определить порядок хэшируемых объектов, изменяемых или иным образом основанных на их значении.
просто потому что это топ Google нажмите, вот простой способ сделать изменяемый объект hashable:
>>> class HashableList(list): ... instancenumber = 0 # class variable ... def __init__(self, initial = []): ... super(HashableList, self).__init__(initial) ... self.hashvalue = HashableList.instancenumber ... HashableList.instancenumber += 1 ... def __hash__(self): ... return self.hashvalue ... >>> l = [1,2,3] >>> m = HashableList(l) >>> n = HashableList([1,2,3]) >>> m == n True >>> a={m:1, n:2} >>> a[l] = 3 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: unhashable type: 'list' >>> m.hashvalue, n.hashvalue (0, 1)Я действительно нашел применение для чего-то подобного при создании класса для приведения записей SQLAlchemy в нечто изменчивое и более полезное для меня, сохраняя при этом их хэш-способность для использования в качестве ключей dict.
неизменяемый означает, что объект не изменится каким-либо существенным образом в течение его жизни. Это расплывчатая, но распространенная идея в языках программирования.
Хэшируемость немного отличается и относится к сравнению.
hashable объект хэшируется, если он имеет хэш-значение, которое никогда изменения в течение его жизни (он нуждается в
__hash__()способ), и может быть по сравнению с другими объектами (он нуждается в__eq__()или__cmp__()метод.) Хэшируемые объекты, которые сравниваются равными, должны иметь одинаковое хэш-значение.все пользовательские классы
__hash__метод, который по умолчанию просто возвращает идентификатор объекта. Таким образом, объект, удовлетворяющий критериям хэшируемости, не обязательно является неизменяемым.объекты любого нового класса, который вы объявите, могут использоваться в качестве ключа словаря, если вы не предотвратите его, например, бросая из
__hash__можно сказать, что все неизменные объектов hashable, потому что если хэш меняется в течение времени жизни объекта, то это означает, что объект видоизменен.
но не совсем. Рассмотрим Кортеж, который имеет список (изменяемый). Некоторые говорят, что кортеж неизменен, но в то же время он несколько не хэшируется (бросает).
d = dict() d[ (0,0) ] = 1 #perfectly fine d[ (0,[0]) ] = 1 #throwsХэшируемость и неизменяемость относятся к объектному экземпляру, а не к типу. Например, объект кортеж типа может быть hashable или нет.
в Python они в основном взаимозаменяемы; поскольку хэш должен представлять содержимое, поэтому он так же изменчив, как и объект, и изменение объекта хэш-значение сделает его непригодным для использования в качестве ключа dict.
в других языках хэш-значение больше связано с идентификатором объектов, а не (обязательно) со значением. Таким образом, для изменяемого объекта указатель может использоваться для запуска хэширования. Предполагая, конечно, что объект не перемещается в памяти (как некоторые GC делают). Такой подход используется, например, в Lua. Это делает изменяемый объект может использоваться в качестве ключа таблицы, но создает несколько (неприятных) сюрпризов для новичков.
в конце концов, наличие неизменяемого типа последовательности (кортежей) делает его более приятным для "многозначных ключей".
Hashable означает, что значение переменной может быть представлено (или, скорее, закодировано) константой -- string, number и т. д. Теперь то, что подвержено изменению (изменчиво), не может быть представлено тем, чего нет. Таким образом, любая переменная, которая является изменяемым, не может быть hashable и, к тому же, только неизменяемые переменные могут быть hashable.
надеюсь, что это помогает ...
Comments