Python交换列表
在python中,当我将一个列表分配给另一个列表时,如:Python交换列表,python,list,iterable-unpacking,python-internals,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在内部交换这些项。检查此程序 a, b = [1, 2], [2, 3] def func(): a, b = b, a import dis dis.dis(func) a, b,
a = [1,2,3]
b = a
现在b和a指向同一个列表。现在考虑两份清单
a = [1,2,3]
b = [4,5,6]
a,b = b,a
现在,它们如何像任何其他数据类型一样进行交换,而不是最终都指向同一个列表?看起来像Python在内部交换这些项。检查此程序
a, b = [1, 2], [2, 3]
def func():
a, b = b, a
import dis
dis.dis(func)
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 (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
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
因此,Python将引用从b
和a
推到堆栈中。因此,现在最上面的元素是a
指向的引用,下一个元素是b
指向的引用。然后,它使用交换堆栈顶部的两个元素。因此,现在,最上面的元素是b
指向的引用,下一个元素是a
指向的引用,然后将堆栈的前两个元素分别分配给a
和b
这就是当我们处理的项目数少于4项时,在赋值语句中排序的方式
如果项目数大于或等于四个,它将构建一个元组并解压缩值。检查此程序
a, b = [1, 2], [2, 3]
def func():
a, b = b, a
import dis
dis.dis(func)
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 (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
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
因为Python赋值首先计算右侧表达式,然后将结果应用于左侧目标
因此,首先,Python将(,)
创建为一个元组,然后将该元组中的第一项分配给a
,将该元组中的第二项分配给b
。这将整齐地交换引用
您可以展开作业,如下所示:
tmp = b, a
a = tmp[0]
b = tmp[1]
现在,它们如何像任何其他数据类型一样进行交换,而不是最终都指向同一个列表
因为从解包元组
b,a
到元组a,b
的那一刻起,您就失去了对原始a
和b
的引用,它们被重新分配。看起来Python没有在这里创建元组。请检查我的答案。没有,因为作业已优化。该评论(在我的手机上)发布得有点早。任务优化;当使用多个赋值时,编译器跳过创建元组。没有意义。但是为了理解发生了什么,想象它是一个元组是很好的。在扩展的赋值示例中,tmp
是一个tuple.Yup。这是我最初的理解。即使是我的第一次编辑也只有基于元组的答案。我只是简单地试了一下dis,结果大吃一惊@SteveJessop:编译器在这两种情况下都会生成一个BUILD\u TUPLE
操作码,但是当LHS上有赋值且只涉及3或2个值时,窥视孔优化器会用ROT\ucode>操作码替换该操作码。对于更多的元素,元组仍然是实际创建的。@MartijnPieters这就是为什么我必须用粗体制作引用。@MartijnPieters得到了你:)请检查我更新的答案,包括元组解包的内容。至于我所说的优化;实际上,它仅限于两个和三个项目的拆包;看看你是否感兴趣。对于两个项目,BUILD\u TUPLE
和UNPACK\u SEQUENCE
替换为ROT\u two
,对于三个项目,替换为ROT\u two
。因为4个项目将需要三个操作码(ROT_-FOUR
,然后ROT_-FOUR
然后ROT_-FOUR
),因此不再值得为其进行优化。@MartijnPieters很高兴您阅读此内容。:)否则,这个答案就会产生误导。更新了那句话。请现在检查