对于用户定义的类型,两个字典键何时是相等的?

2024-04-30 01:43:34 发布

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

我正在编写字典,其中用户定义的类型对象是键,我不明白为什么对于下面的代码,即使下面的对象相等,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.:我是C++开发人员,开始从事Python


Tags: 对象用户nameself类型return字典定义
2条回答

针对您在评论中提出的问题,下面的示例说明了为什么可变类型通常是字典键的坏主意:

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__方法的一部分进行评估的属性)使用描述符,以防止它们容易被修改。你知道吗

我相信还有很多其他的方法,所以了解在字典中查找键的过程是很重要的。你知道吗

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++不同,其中第二个键将不被插入。你知道吗

相关问题 更多 >