问题#1:为什么在同一对象中的容器中会发现NaN。
从文档中:
对于列表,元组,集合,frozenset,dict或collections.deque等容器类型,y中的表达式x等于any(x为e或y中的e为x ==
e)。
这正是我在NaN上观察到的,所以一切都很好。为什么要这个规则?我怀疑这是因为
dict/
set想要诚实地报告它包含某个对象(如果该对象确实存在于其中)(即使
__eq__()出于某种原因选择报告该对象不等于自身)。
问题2:为什么NaN的哈希值与0相同?
从文档中:
由内置函数hash()调用,用于对散列集合的成员(包括set,frozenset和dict)进行 *** 作。 hash
()应该返回一个整数。唯一需要的属性是比较相等的对象具有相同的哈希值;建议以某种方式将散列值混合在一起(例如,使用异或),以将对象的组成部分也用作对象比较的一部分。
请注意,此要求仅在一个方向上进行;具有相同散列的对象不必相等!起初我以为是错字,但后来我意识到不是。哈希冲突无论如何都会发生,即使默认情况下也是如此
__hash__()(请参阅此处的出色说明)。容器可以毫无问题地处理碰撞。当然,它们确实最终会使用
==运算符来比较元素,因此,只要它们不相同,它们很容易以多个NaN值结束!尝试这个:
>>> nan1 = float('nan')>>> nan2 = float('nan')>>> d = {}>>> d[nan1] = 1>>> d[nan2] = 2>>> d[nan1]1>>> d[nan2]2
因此,一切工作均按文档记录。但是…非常非常危险!有多少人知道NaN的多种价值可以在一个命令中彼此并存?有多少人会觉得这很容易调试?
我建议将NaN设为
float不支持哈希的子类的实例,因此不能意外地将其添加到
set/中
dict。我将其提交给python-ideas。
最后,我在这里的文档中发现了一个错误:
对于不定义用户定义的类
__contains__(),但不限定__iter__(),x in y如果一些值为truez与x ==z同时迭代产生y。如果在迭代过程中in引发了异常,则好像引发了该异常。最后,尝试使用旧式的迭代协议:如果一个类定义
__getitem__(),x in y则当且仅当存在一个非负整数索引(i例如)x ==y[i],并且所有较低的整数索引都不会引发IndexError异常时,该方法才为true
。(如果引发了其他任何异常,则好像in引发了该异常)。
您可能会注意到,
is与内置容器不同,这里没有提及。我对此感到惊讶,因此我尝试:
>>> nan1 = float('nan')>>> nan2 = float('nan')>>> class Cont:... def __iter__(self):... yield nan1...>>> c = Cont()>>> nan1 in cTrue>>> nan2 in cFalse
如您所见,先检查身份,然后再检查
==-与内置容器一致。我将提交报告以修复文档。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)