Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Object of custom type as dictionary key

What must I do to use my objects of a custom type as keys in a Python dictionary (where I don't want the "object id" to act as the key) , e.g.

class MyThing:     def __init__(self,name,location,length):             self.name = name             self.location = location             self.length = length 

I'd want to use MyThing's as keys that are considered the same if name and location are the same. From C#/Java I'm used to having to override and provide an equals and hashcode method, and promise not to mutate anything the hashcode depends on.

What must I do in Python to accomplish this ? Should I even ?

(In a simple case, like here, perhaps it'd be better to just place a (name,location) tuple as key - but consider I'd want the key to be an object)

like image 548
Anonym Avatar asked Feb 04 '11 18:02

Anonym


People also ask

Can you use an object as a dictionary key?

Dictionaries in Python Almost any type of value can be used as a dictionary key in Python. You can even use built-in objects like types and functions. However, there are a couple restrictions that dictionary keys must abide by. First, a given key can appear in a dictionary only once.

Can a dictionary key be an object Python?

Properties of Dictionary KeysThey can be any arbitrary Python object, either standard objects or user-defined objects. However, same is not true for the keys.

Can a custom struct be used as a dictionary key Swift?

Any type that conforms to the Hashable protocol can be used as a dictionary's Key type, including all of Swift's basic types. You can use your own custom types as dictionary keys by making them conform to the Hashable protocol.

Can a dictionary key be an object c#?

The keys in a dictionary can be a reference type, i.e., objects.


2 Answers

You need to add 2 methods, note __hash__ and __eq__:

class MyThing:     def __init__(self,name,location,length):         self.name = name         self.location = location         self.length = length      def __hash__(self):         return hash((self.name, self.location))      def __eq__(self, other):         return (self.name, self.location) == (other.name, other.location)      def __ne__(self, other):         # Not strictly necessary, but to avoid having both x==y and x!=y         # True at the same time         return not(self == other) 

The Python dict documentation defines these requirements on key objects, i.e. they must be hashable.

like image 53
6502 Avatar answered Sep 21 '22 05:09

6502


An alternative in Python 2.6 or above is to use collections.namedtuple() -- it saves you writing any special methods:

from collections import namedtuple MyThingBase = namedtuple("MyThingBase", ["name", "location"]) class MyThing(MyThingBase):     def __new__(cls, name, location, length):         obj = MyThingBase.__new__(cls, name, location)         obj.length = length         return obj  a = MyThing("a", "here", 10) b = MyThing("a", "here", 20) c = MyThing("c", "there", 10) a == b # True hash(a) == hash(b) # True a == c # False 
like image 23
Sven Marnach Avatar answered Sep 20 '22 05:09

Sven Marnach