【发布时间】:2014-01-02 04:39:51
【问题描述】:
在python中,当我将一个列表分配给另一个时,例如:
a = [1,2,3]
b = a
现在 b 和 a 指向同一个列表。现在考虑两个列表,
a = [1,2,3]
b = [4,5,6]
a,b = b,a
现在它们如何像任何其他数据类型一样被交换并且最终都指向同一个列表?
【问题讨论】:
标签: python list iterable-unpacking python-internals
在python中,当我将一个列表分配给另一个时,例如:
a = [1,2,3]
b = a
现在 b 和 a 指向同一个列表。现在考虑两个列表,
a = [1,2,3]
b = [4,5,6]
a,b = b,a
现在它们如何像任何其他数据类型一样被交换并且最终都指向同一个列表?
【问题讨论】:
标签: python list iterable-unpacking python-internals
看起来 Python 在内部交换了项目。检查这个程序
a, b = [1, 2], [2, 3]
def func():
a, b = b, a
import dis
dis.dis(func)
输出
4 0 LOAD_FAST 0 (b)
3 LOAD_FAST 1 (a)
6 ROT_TWO
7 STORE_FAST 1 (a)
10 STORE_FAST 0 (b)
13 LOAD_CONST 0 (None)
16 RETURN_VALUE
因此,Python 将来自b 和a 的references 推送到LOAD_FAST 的堆栈中。所以,现在最上面的元素是a 指向的引用,下一个是b 指向的引用。然后它使用ROT_TWO 交换堆栈的顶部两个元素。所以,现在,最上面的元素是b指向的引用,下一个是a指向的引用,然后将堆栈的顶部两个元素分别分配给a和b@987654323 @。
这就是赋值语句中的排序方式,当我们处理的项目数少于 4 时。
如果项目的数量大于或等于四个,它会构建一个元组并解包这些值。检查这个程序
a, b, c, d = [1, 2], [2, 3], [4, 5], [5, 6]
def func():
a, b, c, d = d, c, b, a
import dis
dis.dis(func)
输出
4 0 LOAD_FAST 0 (d)
3 LOAD_FAST 1 (c)
6 LOAD_FAST 2 (b)
9 LOAD_FAST 3 (a)
12 BUILD_TUPLE 4
15 UNPACK_SEQUENCE 4
18 STORE_FAST 3 (a)
21 STORE_FAST 2 (b)
24 STORE_FAST 1 (c)
27 STORE_FAST 0 (d)
30 LOAD_CONST 0 (None)
33 RETURN_VALUE
【讨论】:
references 加粗。
peephole.c。对于两个项目,BUILD_TUPLE 和 UNPACK_SEQUENCE 被替换为 ROT_TWO,对于三个项目,它被替换为 ROT_THREE 然后 ROT_TWO。因为 4 个项目需要 三个 操作码(ROT_FOUR,然后是 ROT_THREE,然后是 ROT_TWO),因此不再值得优化。
因为 Python 赋值 first 计算右侧表达式,然后 将结果应用于左侧目标。
所以,首先,Python 将(<reference to list b>, <reference to list a>) 创建为一个元组,然后将该元组中的第一项分配给a,并将该元组中的第二项分配给到b。这巧妙地交换了引用。
你可以像这样扩展作业来阅读它:
tmp = b, a
a = tmp[0]
b = tmp[1]
【讨论】:
tmp 是一个元组。
dis 并感到惊讶。 :)
BUILD_TUPLE 操作码,但是当 LHS 上存在分配且只有 3 或 2 个值时,窥孔优化器会将该操作码替换为 ROT_ 操作码参与其中。对于更多元素,实际上仍然会创建元组。
现在它们如何像任何其他数据类型一样被交换并且最终都指向同一个列表?
因为当您将元组 b, a解包到元组 a, b 中时,您失去了对原始 a 和 b 的引用,并且它们被重新分配。
【讨论】: