我正在使用字典,其中用户定义的类型对象是键,我无法理解为什么下面的代码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(self.name)
ob = DTest('kkk')
ob1 = DTest('kkk')
dict = {ob:1,ob1:2}
P.S。 :我是开始使用python的C ++开发人员
答案 0 :(得分:0)
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 ++不同,后者不会插入第二个密钥。
答案 1 :(得分:0)
回答你在评论中提出的问题时,这里有一个例子,说明为什么可变类型通常对字典键一个坏主意:
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
到目前为止一切都有效,但如果密钥发生变异会怎样......
# 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
现在,使用户定义的对象不可变并不是世界上最简单的事情,但实际上你关心的是dict键是不可变的。具体来说,您希望确保__hash__
和__eq__
中使用的dict键的属性不可变,或以其他方式保护其免受更改。
最简单但最不灵活的方法是将引用相等性用作__eq__
测试(默认),并将id(self)
用于__hash__
实现。这将确保即使发生变异,也会找到密钥。缺点是你可以在字典中查找密钥的唯一方法就是你已经有了对这个确切对象的引用。
另一种方法是在您将密钥用于某个密钥后,不要改变您用于密钥的对象。可能不是最直观或最强大的,但肯定会奏效。
另一种方法是使用相关的用户定义对象状态创建不可变对象,并将其用作键。有点浪费记忆但很简单并完成工作。
另一种可能是对重要属性使用描述符(那些被评估为__eq__
和__hash__
方法的一部分)以防止它们被轻易修改。
我确信还有很多其他方法,所以你知道在字典中查找按键的过程非常重要。