自定义types的对象作为字典键

我必须做什么来使用自定义types的对象作为Python字典中的键(我不希望“对象ID”作为键),例如

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

如果名称和位置相同,我想使用MyThing作为关键字。 从C#/ Java我习惯于重写并提供一个equals和hashcode方法,并承诺不会改变任何哈希码依赖。

我必须在Python中做什么来完成这个任务? 我应该甚至?

(在一个简单的例子中,就像这里,也许最好是把一个(名称,位置)元组作为键 – 但是考虑我希望键是一个对象)

您需要添加2个方法 ,请注意__hash____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) 

Python dict文档定义了关键对象的这些要求,即它们必须是可散列的 。

Python 2.6或更高版本的替代方法是使用collections.namedtuple() – 它可以节省您编写的任何特殊方法:

 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 

如果您想要特殊的哈希语义,您可以重写__hash__ ,而__cmp____eq__可以使您的类成为键。 比较相等的对象需要具有相同的散列值。

Python期望__hash__返回一个整数,返回Banana()不推荐:)

用户定义的类默认情况下有__hash__ ,正如你所说的,它调用了id(self)

文档中还有一些额外的提示。

从父类inheritance__hash__()方法的类,但改变__cmp__()__eq__()的含义, __cmp__()返回的散列值不再合适(例如,通过切换到基于值的相等概念而不是默认值基于身份的相等性)可以通过在类定义中设置__hash__ = None来明确地将自己标记为不可相干的。 这样做意味着当一个程序试图检索它们的散列值时,不仅类的实例会引发一个适当的TypeError,而且在检查isinstance(obj, collections.Hashable)时它们也将被正确地识别为不可能的(与定义它们的类不同自己的__hash__()明确地引发TypeError)。