Co oznacza „hashable” w Pythonie?


194

Próbowałem przeszukać internet, ale nie mogłem znaleźć znaczenia skrótu.

Kiedy mówią, że przedmioty są hashablelub hashable objectsco to oznacza?


1
Zobacz dokumentację dotyczącą mieszania i __hash__()metody .
ʇsәɹoɈ

5
, który wyszukuje obiekty, które można mieć, ale żaden z linków nie wyjaśnia, co tak naprawdę oznacza
hashable

Odpowiedzi:


181

Ze słownika Python :

Obiekt jest haszowalny, jeśli ma wartość skrótu, która nigdy się nie zmienia w trakcie jego życia (potrzebuje __hash__()metody), i można go porównać do innych obiektów (potrzebuje metody __eq__()lub __cmp__()). Obiekty haszujące, które porównują równe, muszą mieć tę samą wartość skrótu.

Hashability sprawia, że ​​obiekt nadaje się do użycia jako klucz słownika i element członkowski, ponieważ te struktury danych wewnętrznie używają wartości skrótu.

Wszystkie niezmienne wbudowane obiekty Pythona są haszowalne, podczas gdy żadne zmienne kontenery (takie jak listy lub słowniki) nie są. Obiekty będące instancjami klas zdefiniowanych przez użytkownika są domyślnie mieszalne; wszystkie porównują nierówne, a ich wartość skrótu jest ich id().


2
jeśli ma hash valueteraz wartość hash. czy możesz podać jakiś przykład
użytkownik1755071

2
@ user55711: Tutaj wartość skrótu jest wynikiem wywołania __hash__(). Bardziej ogólnie, patrz en.wikipedia.org/wiki/Hash_function
NPE

16
@ TorstenBronger: Ponieważ dwa nierówne obiekty mogą mieć skrót do tej samej wartości. Innymi słowy, mieszanie jest stratne.
NPE

1
W python-2.7.12 wynikiem id(object)jest 16x wynik z object.__hash__(). Tak więc fragment glosariusza jest niepoprawny dla tej wersji - wartość skrótu nie jest id(), ale pochodzi z niej (jak rzeczywiście zauważono w zaktualizowanych dokumentach dla Pythona 2.7.12).
davidA

2
Wiem, że to stary post, ale warto wspomnieć, że skopiowany tutaj zapis słownika nie jest całkowicie poprawny. Możesz umieścić zmienny obiekt (np. Listę) w krotce. Krotka jest wciąż niezmienna, ale możesz zmienić znajdującą się w niej listę, więc nie można jej haszować. Spróbuj hash((1, [2, 3]))zobaczyć to w akcji. Wysłałem prośbę o poprawienie hasła w haszowaniu.
John Riehl

102

Wszystkie odpowiedzi tutaj mają dobre objaśnienie funkcjonalne obiektów w Pythonie, ale uważam, że najpierw należy zrozumieć pojęcie Hashing.

Hashing to koncepcja informatyki, która służy do tworzenia wysokowydajnych struktur danych o pseudolosowym dostępie, w których duża ilość danych ma być szybko przechowywana i dostępna.

Na przykład, jeśli masz 10 000 numerów telefonów i chcesz je przechowywać w tablicy (która jest sekwencyjną strukturą danych, która przechowuje dane w sąsiadujących lokalizacjach pamięci i zapewnia losowy dostęp), ale możesz nie mieć wymaganej ilości ciągłych lokalizacje pamięci.

Możesz więc zamiast tego użyć tablicy o rozmiarze 100 i użyć funkcji skrótu, aby odwzorować zestaw wartości na te same indeksy, a te wartości można zapisać na połączonej liście. Zapewnia to wydajność podobną do tablicy.

Teraz funkcja skrótu może być tak prosta, jak dzielenie liczby z rozmiarem tablicy i przyjmowanie reszty jako indeksu.

Aby uzyskać więcej informacji, zobacz https://en.wikipedia.org/wiki/Hash_function

Oto kolejna dobra referencja: http://interactivepython.org/runestone/static/pythonds/SortSearch/Hashing.html


1
To interesująca perspektywa haszowania. Nie myślałem o tym w ten sposób.
yuvgin

Tabele skrótów @yuvgin są często używane do implementacji rzadkich tablic (tj. podany tutaj przykład).
Eli Korvigo

@EliKorvigo Lubię myśleć o zwykłych tablicach jako po prostu wysoce zoptymalizowanych wersjach tabeli mieszającej.
Mark Ransom,

1
czy możesz napisać prosty kod dotyczący scenariusza tablicy numerów, aby wyjaśnić pojęcie mieszania?
Istiaque Ahmed

18

Wszystko, czego nie można modyfikować (środki, które mogą ulec zmianie) mogą zostać zaszyfrowane. Oprócz funkcji skrótu do wyszukania, jeśli klasa ją ma, np. dir(tuple)i szukając __hash__metody, oto kilka przykładów

#x = hash(set([1,2])) #set unhashable
x = hash(frozenset([1,2])) #hashable
#x = hash(([1,2], [2,3])) #tuple of mutable objects, unhashable
x = hash((1,2,3)) #tuple of immutable objects, hashable
#x = hash()
#x = hash({1,2}) #list of mutable objects, unhashable
#x = hash([1,2,3]) #list of immutable objects, unhashable

Lista niezmiennych typów:

int, float, decimal, complex, bool, string, tuple, range, frozenset, bytes

Lista zmiennych typów:

list, dict, set, bytearray, user-defined classes

Niedawno dowiedziałem się, że Ellipsisjest to również niezmienny typ i może być używany jako klucz do dict.
Gábor Fekete

Można używać nawet klas zdefiniowanych przez użytkownika, ale tylko ich nazwy nie są instancjami. Np .:hash(MyClass)
Gábor Fekete

1
@ Instancje instancji klas zdefiniowanych przez użytkownika są mieszalne, jeśli ich klasy implementują __hash__i __eq__. Co więcej, wszystkie klasy zdefiniowane przez użytkownika implementują te metody (a zatem są haszowalne), ponieważ dziedziczą one metody object(uniwersalna klasa bazowa).
Eli Korvigo

7

W moim rozumieniu, zgodnie ze słownikiem Pythona, podczas tworzenia instancji obiektów, które można mieszać, niezmienna wartość jest również obliczana na podstawie elementów lub wartości instancji. Na przykład tę wartość można następnie wykorzystać jako klucz w nagraniu, jak poniżej:

>>> tuple_a = (1,2,3)
>>> tuple_a.__hash__()
2528502973977326415
>>> tuple_b = (2,3,4)
>>> tuple_b.__hash__()
3789705017596477050
>>> tuple_c = (1,2,3)
>>> tuple_c.__hash__()
2528502973977326415
>>> id(a) == id(c)  # a and c same object?
False
>>> a.__hash__() == c.__hash__()  # a and c same value?
True
>>> dict_a = {}
>>> dict_a[tuple_a] = 'hiahia'
>>> dict_a[tuple_c]
'hiahia'

możemy stwierdzić, że wartość skrótu tuple_a i tuple_c są takie same, ponieważ mają tych samych członków. Kiedy używamy tuple_a jako klucza w dict_a, możemy stwierdzić, że wartość dla dict_a [tuple_c] jest taka sama, co oznacza, że ​​gdy są używane jako klucz w dict, zwracają tę samą wartość, ponieważ wartości skrótu są to samo. W przypadku obiektów, które nie są haszowalne, skrót mieszający jest zdefiniowany jako Brak:

>>> type(dict.__hash__) 
<class 'NoneType'>

Wydaje mi się, że ta wartość skrótu jest obliczana przy inicjalizacji instancji, a nie w sposób dynamiczny, dlatego hahowalne są tylko niezmienne obiekty. Mam nadzieję że to pomoże.


4

Pozwól, że dam ci działający przykład na zrozumienie obiektów możliwych do skrótu w Pythonie. Biorę 2 Tuple dla tego przykładu. Każda wartość w krotce ma unikalną wartość skrótu, która nigdy nie zmienia się w trakcie jej życia. Na tej podstawie ma wartość, porównanie dwóch krotek jest wykonywane. Możemy uzyskać wartość skrótu elementu krotkowego za pomocą Id ().

Porównanie 2 krotekRównoważność między 2 krotkami


26
byłoby to bardziej przydatne jako tekst niż obraz
baxx

7
to zła odpowiedź. id () pokazuje przywołany adres w pamięci, nie jest to wartość skrótu. Aby uzyskać skrót, użyj funkcji __hash __ (). np .: t1 .__ hash __ ()
Vlad

@ascentman Nie wahaj się edytować odpowiedzi, która Twoim zdaniem jest nieprawidłowa. Twoja edycja zostanie poddana recenzji i jeśli zostanie zaakceptowana, otrzymasz za nią niewielką nagrodę punktową.
XavierStuvw

4

W pythonie oznacza to, że obiekt może być składnikiem zestawu w celu zwrócenia indeksu. Oznacza to, że mają unikalną tożsamość / identyfikator.

na przykład w python 3.3:

struktura danych Listy nie są haszowalne, ale struktura danych Krotki są haszowalne.


Hash nie jest tym samym id, co (przybliżony) adres obiektu w pamięci.
poolie

3

Hashable = możliwość skrócenia.

Ok, co to jest hashowanie? Funkcja skrótu to funkcja, która pobiera obiekt, wypowiada ciąg taki jak „Python” i zwraca kod o stałym rozmiarze. Dla uproszczenia załóżmy, że zwracana wartość jest liczbą całkowitą.

Po uruchomieniu skrótu („Python”) w Pythonie 3 otrzymuję 5952713340227947791. Różne wersje Pythona mogą swobodnie zmieniać podstawową funkcję skrótu, więc prawdopodobnie otrzymasz inną wartość. Ważne jest to, że bez względu na to, ile razy teraz uruchamiam hash („Python”), zawsze otrzymam ten sam wynik z tą samą wersją Pythona.

Ale skrót („Java”) zwraca 1753925553814008565. Jeśli więc zmieniam obiekt, który zmieniam, zmienia się również wynik. Z drugiej strony, jeśli obiekt będący skrótem nie zmienia się, wynik pozostaje ten sam.

Dlaczego to ma znaczenie?

Na przykład słowniki Pythona wymagają, aby klucze były niezmienne. Oznacza to, że klucze muszą być obiektami, które się nie zmieniają. W Pythonie ciągi są niezmienne, podobnie jak inne podstawowe typy (int, float, bool). Krotki i frozensety są również niezmienne. Z drugiej strony, listy nie są niezmienne (tzn. Są zmienne), ponieważ można je zmienić. Podobnie, dyktanda są zmienne.

Kiedy więc mówimy, że coś da się ukryć, mamy na myśli to, że jest niezmienne. Jeśli spróbuję przekazać zmienny typ do funkcji hash (), zakończy się ona niepowodzeniem:

>>> hash('Python')
1687380313081734297
>>> hash('Java')
1753925553814008565
>>>
>>> hash([1, 2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> hash({1, 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
>>> hash({1 : 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>>
>>> hash(frozenset({1, 2}))
-1834016341293975159
>>> hash((1, 2))
3713081631934410656

1
Zauważ, że python losowo inicjuje algorytm mieszający na początku każdego procesu. Dlatego faktycznie uzyskasz różne wartości skrótu, jeśli uruchomisz skrót („Python”) dwa razy w różnych procesach.
D Hudson,

2

W Pythonie każdy niezmienny obiekt (taki jak liczba całkowita, wartość logiczna, łańcuch, krotka) jest mieszalny, co oznacza, że ​​jego wartość nie zmienia się w trakcie jego życia. Umożliwia to Pythonowi utworzenie unikatowej wartości skrótu w celu jej identyfikacji, która może być używana przez słowniki do śledzenia unikatowych kluczy i zestawów do śledzenia unikalnych wartości.

Właśnie dlatego Python wymaga, abyśmy używali niezmiennych typów danych dla kluczy w słowniku.


-1

Aby utworzyć tabelę skrótów od zera, wszystkie wartości należy ustawić na „Brak” i zmodyfikować, gdy pojawi się wymaganie. Obiekty haszujące odnoszą się do modyfikowalnych typów danych (słownik, listy itp.). Z drugiej strony zestawów nie można ponownie zainicjować po przypisaniu, więc zestawów nie można haszować. Natomiast wariant set () - frozenset () - podlega skróceniu.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.