2010-12-11 10 views

risposta

18

Qualsiasi oggetto con un metodo __hash__ può essere una chiave di dizionario. Per le classi che scrivi, questo metodo predefinito è restituire un valore in base al largo id (auto), e se l'uguaglianza non è determinata dalla identità per le classi, si può essere sorpresi utilizzandoli come tasti:

>>> 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' 

Modificato nella versione 2.6: __hash__ può ora essere impostato su None per contrassegnare esplicitamente le istanze di una classe come non selezionabili. [__hash__]

class Unhashable(object): 
    __hash__ = None 
6

Il requisito è che l'hash di un oggetto non cambia nel tempo, e che mantiene confronto uguale (==) con il suo valore originale. La tua classe A soddisfa entrambi questi requisiti, quindi rende una chiave di dizionario valida. L'attributo x non è considerato affatto nella codifica, solo l'identità dell'oggetto è.

6

Un oggetto può essere una chiave in un dizionario se è hashable.

Ecco la definizione della hashable dalla documentazione:

Un oggetto è hashable se ha un valore hash che non cambia mai durante la sua vita (ha bisogno di un metodo di __hash__()), e può essere paragonato ad altri oggetti (necessita di un metodo __eq__() o __cmp__()). Gli oggetti che possono essere confrontati devono avere lo stesso valore di hash.

La facilità di utilizzo rende un oggetto utilizzabile come chiave del dizionario e membro dell'insieme, poiché queste strutture dati utilizzano internamente il valore dell'hash.

Tutti gli oggetti incorporati immutabili di Python sono lavabili, mentre non ci sono contenitori modificabili (come elenchi o dizionari). Gli oggetti che sono istanze di classi definite dall'utente sono lavabili per impostazione predefinita; si confrontano tutti ineguali e il loro valore hash è il loro id().

Dal object fornisce un'implementazione predefinita di __hash__, __eq__ e __cmp__ questo significa che qualsiasi cosa derivante dalla object è hashable meno che non sia esplicitamente definito non essere hashable. Non è vietato creare un tipo mutabile che sia lavabile, ma potrebbe non funzionare come si desidera.

1

@ esempio di fred-Nurk sopra per fortuna non funziona più in Python 3, a causa della this change:

Una classe che sostituisce __eq__() e non definisce __hash__() avrà il suo __hash__() implicitamente impostato None. Quando il metodo di una classe __hash__() è None, le istanze della classe saranno sollevano un adeguato TypeError quando un programma tenta di recuperare il loro valore di hash ...

Grazie a Dio per questo.Tuttavia, se si definisce esplicitamente __hash__() per se stessi, è ancora possibile fare cose cattive:

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") 
Problemi correlati