¿Qué debo hacer para usar mis objetos de un tipo personalizado como claves en un diccionario de Python (donde no quiero que el "ID del objeto" actúe como la clave), por ejemplo?
class MyThing:
def __init__(self,name,location,length):
self.name = name
self.location = location
self.length = length
Me gustaría usar MyThing como claves que se consideran iguales si el nombre y la ubicación son los mismos. Desde C # / Java estoy acostumbrado a tener que anular y proporcionar un método igual y de código hash, y prometo no mutar nada de lo que depende el código hash.
¿Qué debo hacer en Python para lograr esto? ¿Debo incluso?
(En un caso simple, como aquí, tal vez sería mejor simplemente colocar una tupla (nombre, ubicación) como clave, pero tenga en cuenta que me gustaría que la clave sea un objeto)
python
dictionary
Seudónimo
fuente
fuente
MyThing
, si tienen el mismoname
ylocation
, para indexar el diccionario para que devuelva el mismo valor, incluso si se crearon por separado como dos "objetos" diferentes.Respuestas:
Necesita agregar 2 métodos , nota
__hash__
y__eq__
:La documentación de dict de Python define estos requisitos en los objetos clave, es decir, deben ser hashaable .
fuente
hash(self.name)
se ve mejor queself.name.__hash__()
, y si lo haces y puedes hacerlohash((x, y))
para evitar XORing a ti mismo.x.__hash__()
así también está mal , porque puede producir resultados incorrectos : pastebin.com/C9fSH7eFand
para__eq__
pero luego pensé "¿por qué no usar tuplas?" porque a menudo hago eso de todos modos (creo que es más legible).__hash__
Sin embargo, por alguna extraña razón, mis ojos no volvieron a preguntar .__ne__()
ha sido "arreglado" .Se debe utilizar una alternativa en Python 2.6 o superior
collections.namedtuple()
: le ahorra escribir cualquier método especial:fuente
Se anula
__hash__
si desea una semántica hash especial,__cmp__
o__eq__
para que su clase sea utilizable como clave. Los objetos que comparan igual deben tener el mismo valor hash.Python espera
__hash__
devolver un número entero,Banana()
no se recomienda regresar :)Las clases definidas por el usuario tienen
__hash__
por defecto que las llamadasid(self)
, como usted notó.Hay algunos consejos adicionales de la documentación :
fuente
__eq__
o__cmp__
.__cmp__
Python te lo da si es una clase definida por el usuario, pero probablemente quieras anularlos de todos modos para acomodar la nueva semántica.cmp
y usar=
en clases de usuario que no anulan estos métodos, uno de ellos debe implementarse para cumplir con el requisito del interrogador de que las instancias con nombre y ubicación similares tengan la misma clave de diccionario.