Python 对于用户定义的类型,两个字典键何时考虑相等?
我正在编写字典,其中用户定义的类型对象是键,我无法理解为什么对于下面的代码,python解释器(2.7)不会抛出错误,即使下面的对象是相等的:Python 对于用户定义的类型,两个字典键何时考虑相等?,python,data-structures,Python,Data Structures,我正在编写字典,其中用户定义的类型对象是键,我无法理解为什么对于下面的代码,python解释器(2.7)不会抛出错误,即使下面的对象是相等的: class DTest: def __init__(self,name): self.name = name def __eq__(self,other): return self.name == other.name def __hash__(self): return hash(
class DTest:
def __init__(self,name):
self.name = name
def __eq__(self,other):
return self.name == other.name
def __hash__(self):
return hash(self.name)
ob = DTest('kkk')
ob1 = DTest('kkk')
dict = {ob:1,ob1:2}
< P.S.:我是C++开发人员,开始从事Python < /P>
class DTest:
def __init__(self,name):
self.name = name
def __eq__(self,other):
return self.name == other.name
def __hash__(self):
return hash(self.name)
ob = DTest('kkk')
ob1 = DTest('kkk')
d = {ob:1,ob1:2}
如果你检查字典中的项目数,它只有1个
len(d)
结果为1
Python以静默方式覆盖上一个条目。注意,这与C++不同,在那里你的第二个键不会被插入。 为了回答您在评论中提出的问题,下面的示例说明了为什么可变类型对于字典键通常是个坏主意:
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
现在,使用户定义的对象不可变并不是世界上最简单的事情,但您真正关心的是dict键是不可变的。具体地说,您希望确保在\uuuuuuuuuuuuuuuuuuuuuuuu散列和\uuuuuuuuueq\uuuuuuu
中使用的dict键的属性是不可变的,或者以某种方式防止更改
最简单但最不灵活的方法是使用引用等式作为\uuuuuueq\uuuuu
测试(默认),并使用id(self)
作为\uuuuuuu散列
实现。这将确保即使发生变异,也能找到密钥。缺点是,在字典中查找键的唯一方法是,如果已经有了对该确切对象的引用
另一种方法是,在某个地方使用对象作为密钥后,不要对该对象进行突变。可能不是最直观或最健壮的,但肯定会起作用
另一种方法是使用相关的用户定义对象状态创建不可变对象,并将其用作键。有点浪费内存,但很简单,可以完成工作
另一种可能是在重要属性上使用描述符(作为\uuuuu eq\uuuu
和\uuuuu hash\uuuu
方法的一部分进行评估的属性),以防止它们容易被修改
我相信还有很多其他方法,所以了解在字典中查找关键字的过程非常重要。您可以在字典中多次输入关键字。旧的将被覆盖。字典中只有一项。Python悄悄地删除了旧条目。与C++不同,在Python中在字典中输入相同的条目不是错误。只是使用一个可变对象作为字典键的一个快速注释通常是一个坏主意。@ JeDeWrdWe如何使用户定义的对象不可变;以及为什么如果Python可改变的数据结构(St/list),解释程序会产生错误。作为键,但对于用户定义的类型,其行为不同。同样,字典键需要实现\uuuuuuuuuuuuuuuuuuu散列和\uuuuuuuueq
,但原因不同--\uuuuuuuuuuuuuuuuuuuu散列帮助确定“bucket”,而\uuuuuuuueq\uuuu
确定键是否相同(因此该值应该被覆盖)或者它们不相同(并且您有一个散列冲突并且两者都应该被存储。(\uuuuu eq\uuuu
有一个默认实现btw(相当于is
),而\uuuuuu散列
没有)。请不要使用dict
作为变量名。这将以相同的名称悄悄地覆盖Python函数!我正要说同样的话!OP,我将编辑我的答案以不使用此名称。@user2357112,不会。谢谢。更正了。基于ID的哈希可以很好地使用pickle。在unp中,ID将不同ickled dict,但dict无论如何都会重新计算哈希值,这样你就不会在错误的哈希表槽中找到对象或类似的东西。实际上我只是在测试自己——谢谢你的提示——将更新帖子。
# Mutate k
k.val = 600
print(d) # {<__main__.MutableIntKey object at 0x00000249DFBFA400>: 'Five'}
print(k in d) # False
print(k in list(d.keys())) # True