StackOverflow 翻译之浮点数键值覆盖整型键值

2018.05.30

Why can a floating point dictionary key overwrite an integer key with the same value?

问题:

我正在 mypythonquiz 答题,然后问题 #45 是回答下面代码的输出结果:

confusion = {}
confusion[1] = 1
confusion['1'] = 2
confusion[1.0] = 4

sum = 0
for k in confusion:
    sum += confusion[k]

print sum

代码输出结果为6,因为键1.01替换了。这让我觉得有些意外,这是一个有用的语言特性吗?

Bakuriu 的高票回答(76votes)

首先,这个现象已经在hash函数的官方文档里解释的很清楚了:

hash(object) Return the hash value of the object(if it has one). Hash values are integers.They are used to quickly compare dictionary keys during a dictionary loopup. Numeric values that compare equal have the same hash value(even if they are of different types, as is the case for 1 and 1.0).

Curabitur blandit tempus porttitor. Nullam quis risus eget urna mollis ornare vel eu leo. Nullam id dolor id nibh ultricies vehicula ut id elit.

其次,object.__hash__文档里指出了hashing的一个限制:

object.hash(self) Called by built-in function hash() and for operations on members of hashed collections including set, frozenset, and dict.__hash__() should return an integer.The only required property is that objects which compare equal have the same hash value;

这并不是python独有的。Java也有类似的提醒:如果你打算实现hashCode函数,那么为了实现正常功能,你必须依据这样的准则实现:x.euqals(y)等价于x.hashCode() == y.hashCode().

所以,在python1.0 == 1,因此对hash函数来说,它就被强制性的实现hash(1.0) == hash(1). 副作用就是在字典中,1.01作为键值是没有区别的,这也就导致了题目中的现象。