<p>针对您在评论中提出的问题,下面的示例说明了为什么可变类型通常是字典键的坏主意:</p>
<pre><code>class MutableIntKey:
def __init__(self, val):
self.val = val
def __eq__(self, other):
return self.val == other.val
def __hash__(self):
return self.val
k = MutableIntKey(5)
d = {k: "Five"}
print(d) # {<__main__.MutableIntKey object at 0x00000249DFBFA400>: 'Five'}
print(k in d) # True
</code></pre>
<p>到目前为止一切正常,但是如果钥匙发生了变异。。。你知道吗</p>
<pre><code># Mutate k
k.val = 600
print(d) # {<__main__.MutableIntKey object at 0x00000249DFBFA400>: 'Five'}
print(k in d) # False
</code></pre>
<p>现在,字典不“认为”关键是在字典里。你知道吗</p>
<p>但实际上,关键是。。。你知道吗</p>
<pre><code>print(k in list(d.keys())) # True
</code></pre>
<p>现在,使用户定义的对象不可变并不是世界上最简单的事情,但是您真正关心的是dict键是不可变的。具体来说,您希望确保在<code>__hash__</code>和<code>__eq__</code>中使用的dict键的属性是不可变的,或者以某种方式防止更改。你知道吗</p>
<p>最简单但最不灵活的方法是使用引用相等作为<code>__eq__</code>测试(默认),并使用<code>id(self)</code>作为<code>__hash__</code>实现。这将确保即使发生了变异,也能找到密钥。缺点是,在字典中查找键的唯一方法是如果已经有了对该对象的引用。你知道吗</p>
<p>另一种方法是,在某个地方将对象用作密钥之后,不要对该对象进行突变。可能不是最直观或最强大的,但肯定会工作。你知道吗</p>
<p>另一种方法是使用相关的用户定义对象状态创建一个不可变对象,并将其用作键。有点浪费内存,但很简单,可以完成工作。你知道吗</p>
<p>另一种可能是对重要属性(作为<code>__eq__</code>和<code>__hash__</code>方法的一部分进行评估的属性)使用描述符,以防止它们容易被修改。你知道吗</p>
<p>我相信还有很多其他的方法,所以了解在字典中查找键的过程是很重要的。你知道吗</p>