对象作为python词典中的键

时间:2011-02-09 20:34:41

标签: python dictionary

我正在尝试将一个对象用作python字典中的一个键,但它的表现方式我无法理解。

首先,我创建一个以对象为关键字的字典:

package_disseminators = {
  ContentType("application", "zip", "http://other/property") : "one",
  ContentType("application", "zip") : "two"
}

现在创建另一个与关键对象“相同”的对象。

content_type = ContentType("application", "zip", "http://other/property")

我已经为ContentType对象提供了自定义__eq__和自定义__str__方法,因此__eq__方法会比较__str__值。

现在,一些交互式python:

>>> for key in package_disseminators:
...     if key == content_type:
...             print "match"
...     else:
...             print "no match"
... 
no match
match

>>> content_type in package_disseminators.keys()
True

好的,所以看起来我的对象肯定被正确识别为一个键,所以:

>>> package_disseminators[content_type]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: (& (type="application/zip") (packaging="http://other/property") )

呃......好吗?所以content_type在package_disseminators.keys()列表中,但不是密钥?

>>> package_disseminators.has_key(content_type)
False

显然不是。

我认为Python用于确定相等性的比较过程在列表上的直接“in”语句和实际查找dict中的键之间有所不同,但我不知道如何。任何提示或见解?

2 个答案:

答案 0 :(得分:25)

来自python文档:

  

字典的键几乎是   任意值。不是的值   hashable,即包含的值   列表,词典或其他可变的   类型(按值比较   而不是通过对象身份)可能   不能用作钥匙。

Hashable定义如下

  

如果对象具有哈希值,则该对象是可清除的   在其期间永远不会改变的价值   一生(需要一个__hash__()   方法),并可以与其他人进行比较   对象(它需要__eq__()或   __cmp__()方法)。比较相等的可清洗对象必须具有相同的对象   哈希值。

     

可持续性使对象可用作   字典键和集合成员,   因为这些数据结构使用了   内部哈希值。

因此,如果你想这样做,你需要覆盖对象的默认__hash__()方法(请参阅下面的Steven Rumbalski的评论以获得进一步的解释)。


>>> content_type in package_disseminators.keys()
True

我认为这是有效的,因为dict.keys()返回一个列表,__contains__可能会检查相等性,但不会检查相同的哈希值。

答案 1 :(得分:18)

由于dicts是底层的哈希表,因此您需要同时定义__eq____hash__才能使用。

基本的经验法则是:

  • 对于__eq__比较相等的对象,__hash__必须返回相同的哈希值。

根据您的描述,例如

def __hash__(self):
    return hash(str(self))

应该有用。