哈希函数问题:hash(1) == hash(1.0)
我有一个字典(dict
),里面的键可以是整数(int
)、浮点数(float
)或者字符串(string
)。但是我遇到了一个问题:当有一个键是整数,另一个键是浮点数,而且如果把转换成浮点数后等于(也就是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
4 个回答
2
如果你只是想知道它们之间的区别,或许可以试试下面这种简单的方法:
x = '1'
y = 1
hash(type(x) + x) != hash(type(y) + y)
6
把浮点数作为字典的键是不太明智的,因为我们无法保证两个浮点数会被认为是相同的值。
最好的办法是把这些键乘以一个固定的小数位数,然后用这个整数作为键。
补充说明:抱歉,看起来你并不是想要一个带有真实数字键的字典,你只是想根据输入的类型来格式化输出?
7
因为 1 == 1.0
,如果 hash(1)
和 hash(1.0)
不相等的话,会严重影响哈希的意义(因此也会影响字典和集合)。更一般来说,对于所有的 x
和 y
,如果 x == y
成立,那么 hash(x) == hash(y)
也必须成立(当然,没有要求反过来成立的条件)。
所以你的字典 d
只有三个条目,因为你在字典中写的第二个条目覆盖了第一个。如果你想要强制只有相同类型的值才算相等(而不是一般的数字),你需要一个包装器,比如:
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)
根据你的具体需求,你可能还想重写其他方法(比如其他比较方法 __cmp__
或 __le__
,算术方法,__repr__
等等)。无论如何,这样可以让你构建一个类似你需要的字典,只需使用 W(1)
作为键,而不是直接用 1
,用 W(1.0)
而不是直接用 1.0
(你可能不需要对非数字进行包装,虽然如果你选择这样做也没问题,而且如果所有键都被包装,可能会更方便从字典中取值)。