Python中的必考问题2

下面这段代码的输出结果将是什么?请解释。

1
2
3
4
ls = [1, 2, 3, 4, 5]

for ls[-2] in ls:
print(ls[-2])

上面代码输出结果将是:

1
2
3
4
5
1
2
3
3
5

画图来分步理解一下:

1
ls = [1, 2, 3, 4, 5]

创建对象引用,变量 ls 指向一个列表对象,列表中的每个位置指向了对应的值。

接下来使用 for 循环进行迭代,我们知道 for 循环的本质是先用 iter() 方法将可迭代的对象做成一个迭代器(iterator),然后再对其不断地调用 next() 取出值,最后处理 StopIteration 异常。

现在,我们将每一次迭代拆开看一下。

1
ls[-2] = ls[0]

此时,ls[-2] 指向列表中第一个位置所指向的元素,也就是 ls[-2] = 1,此时列表就变成了 ls = [1, 2, 3, 1, 5]

1
ls[-2] = ls[1]

此时,ls[-2] 指向列表中第二个位置所指向的元素,也就是 ls[-2] = 2,此时列表就变成了 ls = [1, 2, 3, 2, 5]

1
ls[-2] = ls[2]

此时,ls[-2] 指向列表中第三个位置所指向的元素,也就是 ls[-2] = 3,此时列表就变成了 ls = [1, 2, 3, 3, 5]

1
ls[-2] = ls[3]

此时,ls[-2] 指向列表中第四个位置所指向的元素,请注意此时列表的第四个位置就是倒数第二个位置,即 ls[3] 等同于 ls[-2],而此时的 ls[-2] 指向的是上一次迭代时所指向的对象,也就是 ls[-2] = ls[-2],进一步地 ls[-2] = 3 而不是 4,此时列表就变成了 ls = [1, 2, 3, 3, 5]

1
ls[-2] = ls[4]

此时,ls[-2] 指向列表中第五个位置所指向的元素,也就是 ls[-2] = 5,此时列表就变成了 ls = [1, 2, 3, 5, 5]

最后我们将每一次迭代过程中的 ls[-2] 所指向的数值汇总,也就是:

1
2
3
4
5
1
2
3
3
5

现在,我们修改代码打印每个元素的内存地址来做进一步的验证:

1
2
3
4
5
6
7
8
9
ls = [1, 2, 3, 4, 5]

for idx, val in enumerate(ls):
print('ID of ls[%s] is %s' % (idx, id(val)))

for ls[-2] in ls:
print("\033[0;33m The value of ls[-2] is \033[0m", ls[-2], end=' ; ')
print("\033[0;32m ls is \033[0m", ls, end=' ; ')
print("\033[0;31m ID of ls[-2] is \033[0m", id(ls[-2]))

最后得到的执行结果说明我们的推算是正确的:

有钱任性,请我吃包辣条
0%