2015-03-24 24 views
26

Diciamo che ho un dizionario:Perché non posso chiamare hash() su un metodo apparentemente lavabile di un'istanza non cancellabile?

>>> d = {} 

Ha un metodo di clear():

>>> d.clear 
<built-in method clear of dict object at 0x7f209051c988> 

... che ha un attributo __hash__:

>>> d.clear.__hash__ 
<method-wrapper '__hash__' of builtin_function_or_method object at 0x7f2090456288> 

... che è callable:

>>> callable(d.clear.__hash__) 
True 

Quindi perché non posso farlo?

>>> hash(d.clear) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'dict' 

Nota: so che dict oggetti sono nel calcolo dell'hash - Sono curioso di sapere perché questa restrizione si estende ai loro metodi, anche se, come notato sopra, sembrano sostenere il contrario?

risposta

33

È un metodo associato e i metodi associati hanno un riferimento a self, ad es. il dizionario. Ciò rende il metodo invalicabile.

È possibile hash non legato dict.clear metodo:

>>> d = {} 
>>> d.clear.__self__ 
{} 
>>> d.clear.__self__ is d 
True 
>>> hash(d.clear) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unhashable type: 'dict' 
>>> hash(dict.clear) 
-9223372036586189204 

metodi su istanze che sono hashable essi stessi essere hashable, in modo che il tipo di oggetto per il built-in metodi vincolati implementa un metodo __hash__ ma rilanci TypeError quando l'attributo __self__ non è lavabile. Ciò è coerente con la documentazione del metodo object.__hash__; se è possibile impostarlo su None o non implementarlo affatto, allora è preferibile, ma per questi casi in cui l'hashability è noto solo al runtime, l'aumento di TypeError è l'unica opzione disponibile.

11

Martijn ha ragione, come spesso è. Se si dispone di una sottoclasse dict che fa implementare il metodo __hash__, anche i metodi bound diventare hashable

class MyHashableDict(dict): 
    def __hash__(self): 
     return 42 

x = MyHashableDict() 
print(x, hash(x), hash(x.clear)) 

y = {} 
print(y, hash(y.clear)) 

uscita:

{} 42 287254 
Traceback (most recent call last): 
    File "y.py", line 9, in <module> 
    print(hash(y.clear)) 
TypeError: unhashable type: 'dict'