正如标题所示,我有一个关于更改集合中的对象的问题,使得它们变得完全相同(在集合的眼睛中).只是好奇.
关于Python,我问这个问题,但如果它是可推广的,请随意这样做.
如果我在Python中正确理解,Set iterable将通过等同它们的哈希来确定对象是否"相等".因此对于对象a和b,这将是:
hash(a) == hash(b)
Run Code Online (Sandbox Code Playgroud)
对于任何对象,你让你可以覆盖标准的哈希函数,__hash__以特定的喜好.
假设您创建一个哈希函数,该函数接受对象中的几个或所有对象,并使用哈希的组合作为自己的对象(例如,通过对它们进行OR运算).
现在,如果你在一个Set中有几个最初不同的对象,并因此遍历该Set并改变其内部对象匹配的对象,那么Set会发生什么?他们是否会留在那里,或者他们会被踢出去,还是我们需要等到对该套装进行操作?或者我们在某处提出了一些错误?
考虑这个测试:
class A:
def __init__(self, h):
self.h = h
def __hash__(self):
return self.h
x = A(1)
y = A(2)
a = {x, y}
print x in a, y in a
print a
print "----"
x.h = 2
print x in a, y in a
print a
Run Code Online (Sandbox Code Playgroud)
结果:
True True
set([<__main__.A instance at 0x10d94fd40>, <__main__.A instance at 0x10d94fd88>])
----
False True
set([<__main__.A instance at 0x10d94fd40>, <__main__.A instance at 0x10d94fd88>])
Run Code Online (Sandbox Code Playgroud)
如您所见,第一个对象x仍然存在,但in运算符报告不是.为什么会这样?
根据我的理解,Set对象是使用哈希表实现的,哈希表通常具有如下结构:
hash_value => list of objects with this hash value
another_hash_value => list of objects with this hash value
Run Code Online (Sandbox Code Playgroud)
当Set回答in请求时,它首先计算参数的哈希值,然后尝试在相应的列表中找到它.我们的套装a最初是这样的:
1 => [x]
2 => [y]
Run Code Online (Sandbox Code Playgroud)
现在,我们更改了x哈希并询问该对象是否在那里.该集合计算哈希值(现在是2)尝试x在第二个列表中定位并失败 - 因此False.
为了让事情变得更有趣,让我们做
a.add(x)
print x in a, y in a
print a
Run Code Online (Sandbox Code Playgroud)
结果:
True True
set([<__main__.A instance at 0x107cbfd40>,
<__main__.A instance at 0x107cbfd88>,
<__main__.A instance at 0x107cbfd40>])
Run Code Online (Sandbox Code Playgroud)
现在我们在集合中有两次相同的对象!如您所见,没有自动调整也没有错误.Python是一种成熟的语言,总是假设你知道自己在做什么.
不允许以更改其哈希值的方式修改集合的成员.
在Python中,您只能在一个集合中存储可散列对象.从文档(强调我的):
如果一个对象具有一个在其生命周期内永远不会改变的哈希值(它需要一个
__hash__()方法),并且可以与其他对象(它需要一个__eq__()或多个__cmp__()方法)进行比较,则该对象是可清除的.比较相等的可哈希对象必须具有相同的哈希值.Hashability使对象可用作字典键和set成员,因为这些数据结构在内部使用哈希值.
所有Python的不可变内置对象都是可清除的,而没有可变容器(例如列表或字典).默认情况下,作为用户定义类实例的对象是可清除的; 他们都比较不平等(除了他们自己),他们的哈希值是他们的
id().
如果你违反了这份合同(正如你在提出的问题中提出的那样),该套装无法完成任务并且所有赌注都已关闭.
修改集合成员的正确方法是删除,更改和重新添加.这将按照您的预期行事.
[集合]将通过等同它们的哈希来确定对象是否"相等"
这不太正确.比较散列不能用于确定对象是否相等.它只能用于确定对象不相等.这是一个微妙但重要的区别.
| 归档时间: |
|
| 查看次数: |
141 次 |
| 最近记录: |