如果您在dict 中插入键值对,python 会检查该键是否已存在,如果存在,它将替换当前值。
这个检查是这样的:
def hash_and_value_equal(key1, key2):
return hash(key1) == hash(key2) and key1 == key2
因此不仅值必须相等,而且它们的hash 也必须相等。不幸的是,True 和 1 以及 False 和 0 将被视为相同的键:
>>> hash_and_value_equal(0, False)
True
>>> hash_and_value_equal(1, True)
True
因此它们替换了值(但不是键):
>>> a = {1: 0}
>>> a[True] = 2
>>> a
{1: 2}
>>> a = {False: 0}
>>> a[0] = 2
>>> a
{False: 2}
我已经展示了手动添加密钥的情况,但是使用dict literal时所采取的步骤是相同的:
>>> a = {False: 0, 0: 2}
>>> a
{False: 2}
或dict-builtin:
>>> a = dict(((0, 0), (False, 2)))
>>> a
{0: 2}
如果您编写自己的类并希望将它们用作字典中的潜在键,这可能非常重要。根据您对 __eq__ 和 __hash__ 的实现,它们将替换也不会替换相等但不相同的键的值:
class IntContainer(object):
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other
def __hash__(self):
# Just offsetting the hash is enough because it also checks equality
return hash(1 + self.value)
>>> hash_equal(1, IntContainer(1))
False
>>> hash_equal(2, IntContainer(1))
False
所以这些不会替换现有的整数键:
>>> a = {1: 2, IntContainer(1): 3, 2: 4}
>>> a
{1: 2, <__main__.IntContainer at 0x1ee1258fe80>: 3, 2: 4}
或被视为相同密钥的东西:
class AnotherIntContainer(IntContainer):
def __hash__(self):
# Not offsetted hash (collides with integer)
return hash(self.value)
>>> hash_and_value_equal(1, AnotherIntContainer(1))
True
这些现在将替换整数键:
>>> a = {1: 2, AnotherIntContainer(1): 5}
>>> a
{1: 5}
唯一真正重要的是要记住,如果对象及其哈希值相等,则字典键是相等的。