2010-12-11 14 views

Respuesta

18

Cualquier objeto con un método __hash__ puede ser una clave de diccionario. Para las clases que escribe, este método por defecto es devolver un valor basan fuera Identificación del (auto), y si la igualdad no está determinada por la identidad de esas clases, puede que se sorprenda al utilizarlos como claves:

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

Se modificó en la versión 2.6: __hash__ ahora puede establecerse en None para indicar explícitamente que las instancias de una clase son inigualables. [__hash__]

class Unhashable(object): 
    __hash__ = None 
6

El requisito es que el hash de un objeto no cambia con el tiempo, y que mantiene la comparación de igual (==) con su valor original. Su clase A cumple estos dos requisitos, por lo que crea una clave de diccionario válida. El atributo x no se considera en absoluto en la codificación, solo la identidad del objeto es.

6

Un objeto kan puede ser una clave en un diccionario si es hashable.

Aquí es la definición de hashable de la documentación:

un objeto es hashable si tiene un valor hash que nunca cambia durante su vida útil (se necesita un método __hash__()), y se puede comparar con otra objetos (necesita un método __eq__() o __cmp__()). Los objetos que se pueden comparar y que son iguales deben tener el mismo valor hash.

La capacidad de acceso hace que un objeto se pueda utilizar como una clave de diccionario y un miembro del conjunto, porque estas estructuras de datos usan internamente el valor hash.

Todos los objetos incorporados inmutables de Python son hashable, mientras que no hay contenedores mutables (como listas o diccionarios). Los objetos que son instancias de clases definidas por el usuario son manejables por defecto; todos ellos comparan desigual, y su valor hash es su id().

Desde object proporciona una implementación predeterminada de __hash__, __eq__ y __cmp__ esto significa que cualquier cosa que deriva de object es hashable a menos que se defina explícitamente no ser hashable. No está prohibido crear un tipo mutable que sea hashable, pero puede que no se comporte como lo desee.

1

@ ejemplo de Fred-Nurk anteriormente por suerte ya no funciona en Python 3, debido a this change:

Una clase que anula __eq__() y no define __hash__() tendrá su __hash__() implícitamente establece en None. Cuando el método de una clase __hash__() es None, instancias de la clase lanzará una adecuada TypeError cuando un programa intenta recuperar su valor hash ...

gracias a Dios por eso.Sin embargo, si defines explícitamente __hash__() para ti, aún puedes hacer cosas malvadas:

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") 
Cuestiones relacionadas