本周的PyCoder's Weekly 上分享了一篇小文章,它里面提到的冷知识很有意思,我稍作补充,分享给大家。
它提到的部分问题,读者们可以先思考下:
- 若两个元组相等,即 a==b 且 a is b,那么相同索引的元素(如 a[0] 、b[0])是否必然相等呢?
- 若两个对象的 hash 结果相等,即 hash(a) == hash(b),那么它们是否必然相等呢?
答案当然都为否(不然就不叫冷知识了),大家可以先尝试回答一下,然后再往下看。
-----思考分割线-----
好了,先来看看第一个问题。两个相同的元组 a、b,它们有如下的关系:
> a = (float('nan'),) > b = a > a # (nan,) > b # (nan,) > type(a), type(b) (<type 'tuple'>, <type 'tuple'>) > a == b True > a is b # 即 id(a) == id(b) True > a[0] == b[0] False
以上代码表明:a 等于 b(类型、值与 id 都相等),但是它们的对位元素却不相等。
两个元组都只有一个元素(逗号后面没有别的元素,这是单元素的元组的表示方法,即 len(a)==1 )。float() 是个内置函数,可以将入参构造成一个浮点数。
为什么会这样呢?先查阅一下文档,这个内置函数的解析规则是:
sign ::= "+" | "-" infinity ::= "Infinity" | "inf" nan ::= "nan" numeric_value ::= floatnumber | infinity | nan numeric_string ::= [sign] numeric_value
它在解析时,可以解析前后的空格、前缀的加减号(+/-)、浮点数,除此之外,还可以解析两类字符串(不区分大小写):"Infinity"或"inf",表示无穷大数;“nan”,表示不是数(not-a-number),确切地说,指的是除了数以外的所有东西。
前面分享的第一个冷知识就跟“nan”有关,作为整体,两个元组相等,但是它们唯一的元素却不相等。之所以会这样,因为“nan”表示除了数以外的东西,它是一个范围,所以不可比较。
作为对比,我们来看看两个“无穷大的浮点数”是什么结果:
> a = (float('inf'),) > b = a > a # (inf,) > b # (inf,) > a == b # True > a is b # True > a[0] == b[0] # True
注意最后一次比较,它跟前面的两个元组恰好相反,由此,我们可以得出结论:两个无穷大的浮点数,数值相等,而两个“不是数的东西”,数值不相等。
化简一下,可以这样看:
> a = float('inf') > b = float('inf') > c = float('nan') > d = float('nan') > a == b # True > c == d # False
以上就是第一个冷知识的揭秘。接着看第二个:
> hash(float('nan')) == hash(float('nan')) True
前面刚说了两个“不是数的东西”不相等,这里却显示它们的哈希结果相等,这挺违背常理的。
我们可以推理出一条简单的结论:不相等的两个对象,其哈希结果可能相等。
原因在于,hash(float('nan')) 的结果等于 0,它是个固定值,作比较时当然就相等了。
其实,关于 hash() 函数,还埋了一个彩蛋:
> hash(float('inf')) # 314159 > hash(float('-inf')) # -314159
有没有觉得这个数值很熟悉啊?它正是圆周率的前五位 3.14159,去除小数点后的结果。在早期的 Python 版本中,负无穷大数的哈希结果其实是 -271828,正是取自于自然对数 e。这两个数都是硬编码在 Python 解释器中的,算是某种致敬吧。
由于 float('nan') 的哈希值相等,这通常意味着它们不可以作为字典的不同键值,但是事实却出人意料:
> a = {float('nan'): 1, float('nan'): 2} > a {nan: 1, nan: 2} # 作为对比: > b = {float('inf'): 1, float('inf'): 2} > b {inf: 2}
如上所示,两个 nan 键值在表示上一模一样(注意,它们没有用引号括起来),它们可以共存,而 inf 却只能归并成一个,再次展示出了 nan 的神奇。
好了,两个很冷的小知识分享完毕,背后的原因都在于 float() 取浮点数时,Python 允许了 nan(不是数)的存在,它表示不确切的存在,所以导致了这些奇怪的结果。
最后,我们作下小结:
- 包含 float('nan') 的两个元组,当做整体作比较时,结果相等;两个相等的元组,其对位的元素可能不相等
- float('nan') 表示一个“不是数”的东西,它本身不是确定值,两个对象作比较时不相等,但是其哈希结果是固定值,作比较时相等;可用作字典的键值,而且是不冲突的键值
- float('inf') 表示一个无穷大的浮点数,可看作确定的值,两个对象做比较时相等,其哈希结果也相等;可用作字典的键值,但是会产生冲突
- float('nan') 的哈希结果为 0,float('inf') 的哈希结果为 314159
参考资料:
https://docs.python.org/3/library/functions.html#float
https://www.pythondoeswhat.com/2019/09/welcome-to-float-zone.html
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对的支持。
免责声明:本站资源来自互联网收集,仅供用于学习和交流,请遵循相关法律法规,本站一切资源不代表本站立场,如有侵权、后门、不妥请联系本站删除!
更新日志
- 凤飞飞《我们的主题曲》飞跃制作[正版原抓WAV+CUE]
- 刘嘉亮《亮情歌2》[WAV+CUE][1G]
- 红馆40·谭咏麟《歌者恋歌浓情30年演唱会》3CD[低速原抓WAV+CUE][1.8G]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[320K/MP3][193.25MB]
- 【轻音乐】曼托凡尼乐团《精选辑》2CD.1998[FLAC+CUE整轨]
- 邝美云《心中有爱》1989年香港DMIJP版1MTO东芝首版[WAV+CUE]
- 群星《情叹-发烧女声DSD》天籁女声发烧碟[WAV+CUE]
- 刘纬武《睡眠宝宝竖琴童谣 吉卜力工作室 白噪音安抚》[FLAC/分轨][748.03MB]
- 理想混蛋《Origin Sessions》[320K/MP3][37.47MB]
- 公馆青少年《我其实一点都不酷》[320K/MP3][78.78MB]
- 群星《情叹-发烧男声DSD》最值得珍藏的完美男声[WAV+CUE]
- 群星《国韵飘香·贵妃醉酒HQCD黑胶王》2CD[WAV]
- 卫兰《DAUGHTER》【低速原抓WAV+CUE】
- 公馆青少年《我其实一点都不酷》[FLAC/分轨][398.22MB]
- ZWEI《迟暮的花 (Explicit)》[320K/MP3][57.16MB]