Skip to main content
 首页 » 编程设计

python之散列函数问题 : hash(1) == hash(1. 0)

2025年05月04日7itcoder

我有一个 dict 实例,其中 int、float、string 作为键,但是问题是当 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 == 1.0 以来,如果 hash(1) != hash(1.0) 会严重破坏散列的语义(因此也破坏了字典和集合) 。更一般地说,对于所有 x,x == y 必须始终是 hash(x) == hash(y)和 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 (您可能不需要包装非数字,尽管如果您选择这样做也没有坏处,并且如果所有键都可以简化从字典中的检索同样包裹)。