Python 哈希函数有问题:哈希(1)=哈希(1.0)
我有一个用Python 哈希函数有问题:哈希(1)=哈希(1.0),python,hash,dictionary,Python,Hash,Dictionary,我有一个用ints、floats、strings作为键的dict实例,但问题是当有a作为int和b作为float和float(a)==b时,它们的散列值是相同的,这就是我不想得到的,因为在这种情况下,为了得到相应的值,我需要唯一的散列值 例如: d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0} d[1] == '1.0' d[1.0] == '1.0' d['1'] == 1 d['1.0'] == 1.0 我需要的是: d = {1:'1', 1.0:'1.0
int
s、float
s、string
s作为键的dict
实例,但问题是当有a
作为int
和b
作为float
和float(a)==b
时,它们的散列值是相同的,这就是我不想得到的,因为在这种情况下,为了得到相应的值,我需要唯一的散列值
例如:
d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0}
d[1] == '1.0'
d[1.0] == '1.0'
d['1'] == 1
d['1.0'] == 1.0
我需要的是:
d = {1:'1', 1.0:'1.0', '1':1, '1.0':1.0}
d[1] == '1'
d[1.0] == '1.0'
d['1'] == 1
d['1.0'] == 1.0
这并不能解决您的问题,但可以从以下方面入手: 实现者应该小心地使相等的数字相等,并将它们散列为相同的值
你能把浮点值设为1.00001或类似的值吗?这并不能解决你的问题,但可以从以下方面入手: 实现者应该小心地使相等的数字相等,并将它们散列为相同的值
将浮点值设为1.00001或类似的值可以吗?将浮点值用作字典键是“不明智的”,无法保证两个浮点值的计算结果相同 最好的方法是将这些键相乘到预定的小数位数,并使用该整数作为键
编辑:很抱歉,您似乎不想要带有实数键的dict,您只想根据输入类型格式化输出?使用浮点作为字典键是“不明智的”,无法保证两个浮点将计算为相同的值 最好的方法是将这些键相乘到预定的小数位数,并使用该整数作为键
编辑:很抱歉,您似乎不想要带有实数键的dict,您只需要根据输入类型格式化输出?由于
1==1.0
,如果hash(1)!=哈希(1.0)
。更一般地说,对于所有x
和y
,必须始终是x==y
意味着hash(x)==hash(y)
(当然没有条件要求反向蕴涵成立)
因此,您的dictd
只有三个条目,因为您在dict显示中写入的第二个条目覆盖了第一个条目。如果需要强制仅在相同类型之间保持相等(与更一般的数字相反),则需要一个包装器,例如:
class W(object):
def __init__(self, x):
self.x = x
self.t = type(x)
def __eq__(self, other):
t = type(other)
if t != type(self):
return False
return self.x == other.x and self.t == other.t
def __hash__(self):
return hash(self.x) ^ hash(self.t)
def __getattr__(self, name):
return getattr(self.x, name)
根据您的具体需要,您可能还希望覆盖其他方法(其他比较方法,如
\uu cmp\uuuuu
或\uuuu le\uuuuuu
、算术方法、\uu repr\uuuu
等)。无论如何,这将允许您构建与所需类似的dict,只需将其用作键W(1)
而不是裸1
和W(1.0)
而不是裸1.0
(您可能不需要包装非数字,但如果您选择这样做也没有坏处,而且如果所有键都被同等包装,则可以轻松地从dict检索)。由于1==1.0
,如果是哈希(1)!=hash(1.0)的情况,它将可怕地破坏哈希的语义(因此也会破坏dicts和set)
。更一般地说,对于所有x
和y
,必须始终是x==y
意味着hash(x)==y
(当然,没有条件要求反向蕴涵成立)
因此,您的dictd
只有三个条目,因为您在dict显示中写入的第二个条目覆盖了第一个条目。如果您需要强制仅在相同类型之间保持相等(而不是更一般的数字),则需要一个包装器,例如:
class W(object):
def __init__(self, x):
self.x = x
self.t = type(x)
def __eq__(self, other):
t = type(other)
if t != type(self):
return False
return self.x == other.x and self.t == other.t
def __hash__(self):
return hash(self.x) ^ hash(self.t)
def __getattr__(self, name):
return getattr(self.x, name)
根据您的具体需要,您可能还希望覆盖其他方法(其他比较方法,如
\uuu cmp\uuu
或\uuu le\uuuu
、算术方法、\uu repr\uuu
等)。无论如何,这将允许您构建一个类似于您所需的dict,只需用作键W(1)
而不是bare1
和W(1.0)
而不是bare1.0
(您可能不需要包装非数字,但如果您选择这样做也没有坏处,并且如果所有键都被同等包装,则可以轻松地从dict检索).如果你真的只想知道其中的区别,也许可以做一些黑客行为,比如:
x = '1'
y = 1
hash(type(x) + x) != hash(type(y) + y)
如果你真的只想知道两者的区别,也许可以做一些粗俗的事情,比如:
x = '1'
y = 1
hash(type(x) + x) != hash(type(y) + y)
好的一点,但我也知道我可以为所有关键类型创建一个新类,并为所有其他类型创建一个单独的dict,以备需要,其中setitem、getitem和delitem方法可以确定使用哪个dict来存储键和值。好的一点,但我也知道我可以创建一个单独的dict的新类所有关键类型的dict加上所有其他类型的dict,以防我需要它们,其中setitem、getitem和delitem方法可以确定用于存储键和值的dict。包装对象可以被视为一种解决方案,它非常接近我需要的。无论如何,我想知道以下内容:h=hash('a');d={'a':1,h:2};结果是d['a']!=d[h]因为键的散列值相同,但它们的类型不同,这意味着dict方法getitem同时检查键的散列值和键的类型。如果是这样,为什么int和float的检查方式不同?@mtasic,您是在问为什么在每个上下文中
1==1.0
,或者为什么dict
s使用=
而不是其他方法来检查如果你问的是前者,想想:如果5.0*x==5.0*y
,它怎么可能是x!=y
,而不打破算术和代数最基本的期望?如果是后者,如果x==y
但是d[x]!=d[y],那么dict
怎么可能是一个映射呢
?这些都是强大、珍贵、强烈期望的等式、算术和索引的不变属性,类型拜物教并不是打破它们的好理由;等式