2010-12-11 9 views

Odpowiedz

18

Każdy obiekt z metodą __hash__ może być kluczem słownika. Dla klas piszesz, metoda ta domyślnie powrocie wartość opiera się tożsamości (self), a jeśli równość nie jest określana przez tożsamość dla tych klas, może być zaskoczony przez używanie ich jako klucze:

>>> class A(object): 
... def __eq__(self, other): 
...  return True 
... 
>>> one, two = A(), A() 
>>> d = {one: "one"} 
>>> one == two 
True 
>>> d[one] 
'one' 
>>> d[two] 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
KeyError: <__main__.A object at 0xb718836c> 

>>> hash(set()) # sets cannot be dict keys 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'set' 

Zmieniono w wersji 2.6: __hash__ może teraz być ustawione na Brak, aby jawnie oznaczać instancje klasy jako nieobsługiwane. [__hash__]

class Unhashable(object): 
    __hash__ = None 
6

Warunkiem jest to, że skrót przedmiotu nie zmienia się w czasie i utrzymuje w porównaniu równe (==) z pierwotnej wartości. Twoja klasa A spełnia oba te wymagania, więc tworzy ważny klucz słownika. Atrybut x nie jest w ogóle uwzględniany w kluczowaniu, tylko tożsamość obiektu jest.

6

Obiekt może być kluczem w słowniku, jeśli jest to hashable.

Oto definicja hashable z dokumentacji:

Obiekt jest hashable jeśli ma wartość skrótu, który nigdy się nie zmienia w czasie jego trwania (potrzebuje metodę __hash__()) i może być porównywany do innych obiekty (wymaga to metody __eq__() lub __cmp__()). Obiekty z możliwością dopasowania, które są równe, muszą mieć tę samą wartość skrótu.

Hashability czyni obiekt użytecznym jako klucz słownikowy i element zestawu, ponieważ te struktury danych używają wewnętrznej wartości mieszania.

Wszystkie niezmienne wbudowane obiekty Pythona są nieosiągalne, podczas gdy nie ma możliwych do zmieniania kontenerów (takich jak listy lub słowniki). Obiekty będące instancjami klas zdefiniowanych przez użytkownika są domyślnie nieosiągalne; wszystkie porównują nierówności, a ich wartość skrótu jest ich identyfikatorem().

Od object dostarcza implementację domyślnej __hash____eq__ i __cmp__, to znaczy, że coś jest pochodzący z object hashable chyba że zostanie wyraźnie określone, aby nie być hashable. Nie jest zabronione tworzenie modyfikowalnego typu, który jest niehieralny, ale może nie zachowywać się tak, jak chcesz.

1

@ przykład Fred Nurk jest powyżej na szczęście już nie działa w Pythonie 3, z powodu this change:

Klasa, która zastępuje __eq__() i nie definiuje __hash__() będzie miał swoją __hash__() domyślnie ustawiony na None. Gdy metoda klasy __hash__() jest None, instancje klasy podniesie odpowiedniego TypeError gdy program próbuje odzyskać swoją wartość hash ...

Dzięki Bogu za to.Jeśli jednak samodzielnie zdefiniujesz __hash__(), nadal możesz robić złe rzeczy:

class BadHasher: 
    def __init__(self): 
     self.first = True 

    # Implement __hash__ in an evil way. The first time an instance is hashed, 
    # return 1. Every time after that, return 0. 
    def __hash__(self): 
     if self.first: 
      self.first = False 
      return 1 
     return 0 

myobject = BadHasher() 
# We can put this object in a set... 
myset = {myobject} 
# ...but as soon as we look for it, it's gone! 
if myobject not in myset: 
    print("what the hell we JUST put it in there") 
Powiązane problemy