写在之前
Python 提供了很多让使用者觉得舒服至极的功能特性,但是随着不断的深入学习和使用 Python,我发现其中存在着许多玄学的输出与之前预想的结果大相径庭,这个对于初学者来说难以理解,但是在理解它们以后又会觉得是这么的有意思,所以我准备了这个「有趣的 Python 特性」系列,写一些我碰到或看到的一些你所不知道的「奇葩」,这里面会涉及到在 Python2 和 Python3 中的异同,希望大家能从学习的过程中体会到真正的乐趣。
猜不到的结果
首先我们先来看一行代码:
a, b = a[b] = {}, 5
看完上面的代码,现在问题来了,你知道 a,b 的值是多少么?先仔细思考一下。如果思考完毕,请继续往下看。
在交互模式中输出一下,结果如下所示:
>>> a
{5: ({...}, 5)}
>>> b
5
怎么样?猜对了么?我猜大多数人看到这个结果都会很懵圈,就算不说结果,很多人看到最开始的那行代码,也会觉得没有头脑,下面就让我来详细的说一下,为什么是这样。
首先关于赋值语句,很多人都用过,但是更多的只是常用的形式,就是 a = b 这种模式,很少有人去看官方文档中关于赋值语句的形式:
(target_list "=")+ (expression_list | yield_expression)
上面的 expression_list 是赋值语句计算表达式列表,这个可以是单个表达式或者是以逗号分割的列表(如果是后者的话,返回的是元组),并且将单个结果对象从左到右分给目标列表(target_list)中的每一项。
下面我结合这个赋值语句的形式和文章开头的代码详细说一下为什么会出现这样一个我们猜不到的结果:
下面再来看一个简单一些的循环引用的例子:
>>> test_list = test_list[0] = [0]
>>> test_list
[[...]]
>>> test_list[0]
[[...]]
>>> test_list[0][0][0][0] is test_list
True
其实在文章最初时的那行代码中也是像这样的,比如 a[b][0] 和 a 其实是相同的对象,同样 a[b][0][b][0],a[b][0][b][0][b][0],... 都和 a 是相同的对象。
>>> a[b][0][b][0] is a
True
>>> a[b][0] is a
True
如上,我们也可以完全把文章开头的例子拆解成如下形式:
a, b = {}, 5
a[b] = a, b
这样,是不是更好理解一些了呢?