Python:`key not in my-dict`但`key in my_数字键()`

2024-05-12 21:10:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我有个奇怪的情况。我有一句话,self.containing_dict。使用debug探针,我可以看到dict的内容,self是其中的一个键。但是看看这个:

>>> self in self.containing_dict
False
>>> self in self.containing_dict.keys()
True
>>> self.containing_dict.has_key(self)
False

怎么回事?在

(我会注意到这是在weakref回调上执行的一段代码中。)

更新:我被要求展示__hash__self实现。这里是:

^{pr2}$

Tags: keyindebugselffalsetrue内容情况
3条回答

您描述的问题只能由self实现了__eq__(或__cmp__)而没有实现相应的{}而引起。如果您没有实现__hash__方法,通常情况下您不能使用定义__eq__但不能{}的对象作为dict键,但是如果您继承了一个可能会错过的__hash__。在

如果您确实实现了__hash__,那么必须确保它的行为是正确的:在对象的生存期内(或者至少只要对象作为dict键或set项使用),结果必须与__eq__一致。一个对象的散列值必须与它所等于的对象相同(根据它的__eq____cmp__)。一个对象的散列值可能与它不相等的对象不同,但不一定非得如此。这些要求还意味着在对象的生存期内,__eq__的结果不能更改,这就是为什么可变对象通常不能用作dict键。在

如果您的__hash____eq__不匹配,Python将无法在dicts和set中找到该对象,但它仍然会出现在dict.keys()和{}中,这就是您在这里描述的。实现__hash__方法的通常方法是返回__eq____cmp__方法中使用的任何属性的hash()。在

很可能您已经为任何类self定义了自定义哈希和比较,并且您在将self添加到字典后对其进行了变异。在

如果使用可变对象作为字典键,那么在对其进行变异之后,您可能无法在字典中访问它,但它仍将出现在keys()结果中。在

从您的__hash__方法判断,该类存储对其参数的引用,并将其用作哈希。问题是,这些参数与构造对象的代码共享。如果他们改变了参数,散列也会改变,你将无法在它所在的任何字典中找到这个对象。在

论点不必复杂,只要一个简单的列表就可以了。在

In [13]: class Spam(object) :
   ....:     def __init__(self, arg) :
   ....:         self.arg = arg
   ....:     def __hash__(self) :
   ....:         return hash(tuple(self.arg,))

In [18]: l = range(5)

In [19]: spam = Spam(l)

In [20]: hash(spam)
Out[20]: -3958796579502723947

如果我更改作为参数传递的列表,哈希值将更改。在

^{pr2}$

因为字典键是按散列组织的,所以当我使用x in d时,Python做的第一件事就是计算x的散列值,并在字典中查找具有该散列值的内容。问题是,当一个对象的哈希值在放入字典后发生变化时,Python会查看新的哈希值,而不会在那里看到所需的键。使用键列表,强制Python通过相等方式检查每个键,从而绕过哈希检查。在

相关问题 更多 >