字典中的键和 dict.keys() 中的键有什么区别?

What are the differences between key in dict & key in dict.keys()?

我最近遇到 python 2.7 的问题:

class A(object):
    def __init__(self, v):
        self.v = v

    def __eq__(self, other):
        return self.v == other.v

a1 = A(1)
a2 = A(1)

所以:

print a1 == a2  # True

并且:

d = {a1: 1}
print a2 in d.keys()  # True

但是:

print a2 in d  # False

问题是 a2 ind.keys()a2 in d 之间的主要区别是什么?我怎样才能得到a2 in d is True

在 Python 2.7 中,dict.keys returns 键列表和 a2 in d.keys() 将线性迭代所有键以查找 a2 是否在列表。

但是 a2 in d 会根据对象 a2 的散列值在字典中进行 O(1) 查找,以查看键 a2 是否是在 d.


但在你的情况下,问题完全不同。引用 official documentation,

If a class does not define a __cmp__() or __eq__() method it should not define a __hash__() operation either; if it defines __cmp__() or __eq__() but not __hash__(), its instances will not be usable in hashed collections. If a class defines mutable objects and implements a __cmp__() or __eq__() method, it should not implement __hash__(), since hashable collection implementations require that a object’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

由于您没有明确定义 __hash__ 函数,您违反了它们之间的约定,并且 __hash__ 使用基于对象 id 的默认散列,这将a1a2 都不同。因此,即使 a1a2 相似,散列对象也会将它们视为两个不同的对象,因为它们的散列值不同。

要解决这个问题,您需要定义 __hash__ 函数,像这样

class A(object):

    def __init__(self, v):
        self.v = v

    def __eq__(self, other):
        return self.v == other.v

    def __hash__(self):
        return hash(self.v)

a1 = A(1)
a2 = A(1)

d = {a1: 1}
print a2 in d.keys()  # True
print a2 in d         # True