python列表对象相同_python – “list”中的对象与dict中的“object”不同?

本文探讨了Python中列表和字典的成员测试操作,指出在字典中进行成员测试时,对象的哈希值和相等性比较必须保持一致。文章通过示例解释了一个错误的哈希实现如何导致字典成员测试失败,并提供了修复方法。同时强调,如果类定义中包含可变对象,不应实现__hash__方法,以避免哈希冲突。
摘要由CSDN通过智能技术生成

为了了解发生了什么,您必须了解

membership test中的操作符对不同类型的操作.

对于列表,这是很简单的,因为什么列表基本上是:有序的数组,不关心重复.在这里进行会员考试的唯一可能方式是迭代列表,并检查每个项目的相等性.这样的事情

# x in lst

for item in lst:

if x == item:

return True

return False

词典有点不同:它们是哈希表,键是唯一的.哈希表要求密钥是可哈希的,这基本上意味着需要一个明确的函数将该对象转换成一个整数.然后使用该哈希值将密钥/值映射放在哈希表中.

由于散列值确定哈希表中放置项目的位置,所以关键是要相同的对象产生相同的散列值.所以下面的含义是必须的:x == y => hash(x)== hash(y).反过来不一定是真的;使不同的对象产生相同的哈希值是非常有效的.

当执行字典的成员资格测试时,字典将首先查找哈希值.如果可以找到它,它将对所发现的所有项目执行相等检查;如果没有找到哈希值,那么它假定它是一个不同的对象:

# x in dct

h = hash(x)

items = getItemsForHash(dct, h)

for item in items:

if x == item:

return True

# items is empty, or no match inside the loop

return False

由于您在使用针对列表的成员资格测试时获得所需的结果,这意味着您的对象正确实现了相等性比较(__eq__).但是,由于您在使用字典时没有得到正确的结果,似乎有一个__hash__实现与等式比较实现不同步:

>>> class SomeType:

def __init__ (self, x):

self.x = x

def __eq__ (self, other):

return self.x == other.x

def __hash__ (self):

# bad hash implementation

return hash(id(self))

>>> l = [SomeType(1)]

>>> d = { SomeType(1): 'x' }

>>> x = SomeType(1)

>>> x in l

True

>>> x in d

False

请注意,对于Python 2(从对象继承的类)的新样式类,此“错误哈希实现”(基于对象标识)是默认值.所以当你不实现自己的__hash__函数时,它仍然使用它.这最终意味着除非__eq__只执行身份检查(默认值),否则散列函数将不同步.

所以解决方案是以与__eq__中使用的规则相一致的方式实现__hash__.例如,如果比较两个成员self.x和self.y,则应该使用这两个成员的复合哈希.最简单的方法是返回这些值的元组的哈希值:

class SomeType (object):

def __init__ (self, x, y):

self.x = x

self.y = y

def __eq__ (self, other):

return self.x == other.x and self.y == other.y

def __hash__ (self):

return hash((self.x, self.y))

请注意,如果它是可变的,则不应使对象发生哈希:

If a class defines mutable objects and implements an __eq__() method, it should not implement __hash__(), since the implementation of hashable collections requires that a key’s hash value is immutable (if the object’s hash value changes, it will be in the wrong hash bucket).

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值