对象作为python字典中的键

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4950155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 18:18:09  来源:igfitidea点击:

objects as keys in python dictionaries

pythondictionary

提问by Richard J

I'm trying to use an object as a key in a python dictionary, but it's behaving in a way that I can't quite understand.

我正在尝试使用一个对象作为 python 字典中的键,但它的行为方式我不太理解。

First I create a dictionary with my object as the key:

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

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

Now create another object that is "the same" as one which is a key.

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

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

I have given the ContentType object custom __eq__and custom __str__methods, such that the __eq__method compares the __str__values.

我已经给了 ContentType 对象自定义__eq__和自定义__str__方法,以便该__eq__方法比较__str__值。

Now, some interactive python:

现在,一些交互式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

Ok, so it looks like my object is definitely being identified properly as a key, so:

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

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

Er ... ok? So content_type is in the package_disseminators.keys() list, but isn't a key?

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

>>> package_disseminators.has_key(content_type)
False

Apparently not.

显然不是。

I presume that the comparison process that Python uses to determin equality differs between a straight "in" statement on a list and actually looking up a key in a dict, but I don't know how. Any tips or insights?

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

采纳答案by Reiner Gerecke

From the python documentation:

从 python 文档:

A dictionary's keys are almost arbitrary values. Values that are not hashable, that is, values containing lists, dictionaries or other mutable types (that are compared by value rather than by object identity) may not be used as keys.

字典的键几乎是任意值。不可散列的值,即包含列表、字典或其他可变类型(按值而不是按对象标识进行比较)的值不能用作键。

Hashableis defined as follows

Hashable定义如下

An object is hashable if it has a hash value which never changes during its lifetime (it needs a __hash__()method), and can be compared to other objects (it needs an __eq__()or __cmp__()method). Hashable objects which compare equal must have the same hash value.

Hashability makes an object usable as a dictionary key and a set member, because these data structures use the hash value internally.

如果一个对象的哈希值在其生命周期内永远不会改变(它需要一个__hash__()方法),并且可以与其他对象进行比较(它需要一个__eq__()or __cmp__()方法),那么它就是可哈希的。比较相等的可散列对象必须具有相同的散列值。

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

So if you want to do this, you need to override the default __hash__()method on your object (see the comment from Steven Rumbalski below for further explanation).

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



>>> content_type in package_disseminators.keys()
True

I suppose this works because dict.keys()returns a list, and __contains__probably checks for equality, but not for the same hashes.

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

回答by nosklo

Since dicts are hash tables under the hood, you need to define both __eq__and __hash__for that to work.

由于字典是底层的哈希表,因此您需要定义两者__eq____hash__使其工作。

The basic rule of thumb is:

基本的经验法则是:

  • For objects that __eq__compares equal, __hash__must return the same hash.
  • 对于__eq__比较相等的对象,__hash__必须返回相同的哈希值。

From your description, something like

从你的描述来看,类似

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

should work.

应该管用。