探索Python中的神秘行为(一)

图片[1]-探索Python中的神秘行为(一)-山海云端论坛

01

引言

在日常工作之余,我最喜欢的活动之一是在 Stack Overflow 上闲逛。那里有很多关于 Python 的有趣问题。有些问题可能在我们的生活中永远不会遇到,但是背后的知识却相当有趣,甚至比问题本身更有趣。

在本文中,我将挑选出 Python 中一些“神秘”的行为,并尝试解释它们。希望这些知识能够给大家带来一些不同的乐趣 🙂

02

神秘的字典键

你知道 Python 中的字典可以使用任何哈希对象作为键吗?是的,这意味着我们有时甚至可以使用数字作为键。有人可能认为这是一个“好”的主意,因为这样我们可以采用形如 my_dict[1+1] 这样的表达式作为键。但是,最好不要这样使用,我将证明给你看。

举例:

让我们定义一个使用整数、浮点数和字符串作为键的字典。它们的含义都是“1”。如下所示:

<code>my_dict = { 1: 'one (integer)', '1': 'one (string)', 1.0: 'one point zero (float)' }</code>

现在,让我们尝试使用键来获取值。

<code>my_dict[1] my_dict['1'] my_dict[1.0]</code>

运行结果如下:

图片[2]-探索Python中的神秘行为(一)-山海云端论坛

仔细观察上述输出,第一个结果不对,看起来 my_dict[1] 的值已被 my_dict[1.0] 覆盖。让我们调换下字典里键值出现的先后次序。

<code>my_dict = { 1.0: 'one point zero (float)', 1: 'one (integer)', '1': 'one (string)' }</code>

运行结果如下:

图片[3]-探索Python中的神秘行为(一)-山海云端论坛

这一次,my_dict[1] 的值覆盖了 my_dict[1.0]。因此,后来定义的将覆盖前一个。这意味着键值 11.0 是相同的。

03

相关解释

让我们先来看看 Python 官方文档:

hash(object)

返回对象的哈希值(如果有)。哈希值是整数。它们用于在字典查找期间快速比较字典键。相等的数字值具有相同的哈希值(即使它们是不同类型的,例如 1 和 1.0)。

上述官方文档基本上已经说明了原因。我们传入的字典键将被散列成哈希值进行比较,不幸的是,某些不同类型的哈希值是相同的。我们可以通过以下语句验证这一点。

<code>print(hash(1)) print(hash(1.0)) print(hash('1'))</code>

运行结果如下:

图片[4]-探索Python中的神秘行为(一)-山海云端论坛

事实上,1.0 == 1 在 Python 中是 True。因此,必须实现散列函数以确保 hash(1.0) == hash(1)。字典键的神秘行为是其“副作用”。

综上所述,回到问题本身,你还认为用表达式作为字典键是个好主意吗?不,这仍然是一个坏主意。让我们看看下面的例子。

<code>print(hash(10.0 - 9.2)) print(hash(0.8))</code>

运行结果如下:

图片[5]-探索Python中的神秘行为(一)-山海云端论坛

因此,可以推测以下示例也将不会起作用。

<code>my_dict = {0.8: 'zero point eight'} my_dict[10.0 - 9.2]</code>

运行结果:

图片[6]-探索Python中的神秘行为(一)-山海云端论坛

这一次,这两个哈希函数的值是不同的。

为什么?他们不是同一个数字 0.8 吗?

当然不是。10.0 - 9.2 实际上不完全等于 0.8

这是所有平台上典型的二进制浮点数运算问题。

Python 给出了文档来阐明这个问题。

https://docs.python.org/3/tutorial/floatingpoint.html

因此,请不要使用数字作为字典的键。

04

总结

本文重点介绍了 Python 中的神秘行为之不要使用数字作为字典的键的原因,并给出了相关解释和完整的示例。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容