不明白这个显示元组解包的代码

Don't understand this code showing tuple unpacking

提问人:Arun Upreti 提问时间:8/25/2020 最后编辑:martineauArun Upreti 更新时间:8/25/2020 访问量:512

问:

问题:有人可以解释输出吗?为什么等于秒?z2print()

法典:

x=1
y=2
x,y,z=x,x,y
print(y,x,y,z)
z,y,z=x,y,z
print(x,y,z)

输出:

1 1 1 2
1 1 2
python iterable-unpacking 多重赋值

评论

0赞 possum 8/25/2020
因为您正在设置然后打印?zyzprint(y,x,y,z)
1赞 alani 8/25/2020
在创建(第二个)元组后,它会按顺序将其解压缩为 。因此,首先它执行 然后,然后覆盖它刚刚分配的内容。(1, 1, 2)z,y,zz=1y=1z=21
0赞 Rashid 'Lee' Ibrahim 8/25/2020
可能有助于您更好地理解变量交换的工作原理。这是一个从队列中推送和弹出的问题。
1赞 Mark Tolonen 8/25/2020
代码有什么令人困惑的地方?为什么你认为它不应该是 2?
2赞 Mark Tolonen 8/25/2020
再说一次,你到底认为什么是不正确的。说“这是错的,请解释一下”并不能告诉我们你认为它有什么问题。基本上,解释你认为答案应该是什么以及为什么,然后我们可以纠正你的想法:)

答:

1赞 user11597888 8/25/2020 #1

这是因为在 Python 中,您可以在同一行中从左到右声明和分配多个变量值。

x=1
y=2
x,y, ->z<- =x,x, ->y<-  then again, assignments are read from left to right, y is 2 and is passed to z, therefore z is now 2.
print(y,x,y,z)
z,y,z=x,y,z
print(x,y,z)

相同的示例,但更短:

a = 10
b = 99
a, b, c = a, b, b

我们正在分配:

10 to a
99 to b

然后分别a, b, c = 10, 99, 99

在同一说明中,print 动态地采用任意数量的参数。

因此,翻译正在发生的事情是这样的:

x, y, z = 1, 1, 2
print(1, 1, 1, 2)

在您的情况下:

print(y,x,y,z)

保存值:1、1、1、2。

这是因为 x 和 y 保持 1,而值 z 保持值 2,但 y 被打印了两次,因此也可能发生这种情况

print(z, z, z, x, y, y, z)

这将输出:(2, 2, 2, 1, 1, 1, 2)

之后,在您的代码中

z, x, y = 1, 1, 2

  print(1, 1, 2)
1赞 tdelaney 8/25/2020 #2

您可以在教程部分元组和序列中阅读有关元组的信息。在代码中,正在创建和解压缩元组。

例如,在第二个赋值之前,是 。z2

z,y,z=x,y,z

在这里,python 从右侧创建了一个元组,然后在左侧解包。所以,被重新分配给 1,被重新分配给 1......但随后第二次重新分配为 2,覆盖了第一次分配。(1,1,2)zyz

写入时,您将从这些变量引用的对象创建一个元组。这些对象现在具有来自变量和元组的附加引用。一旦创建了这个元组,它就不关心这些变量会发生什么。它没有关于它们的记忆,只有它所引用的内容。x,y,z

剧本,带有连续评论

x=1
y=2
x,y,z=x,x,y        # create tuple (1,1,2) from the right hand side x,x,y
                   # then unpack left hand side: x=1; y=1; z=2.
print(y,x,y,z)
z,y,z=x,y,z        # create a tuple (1,1,2) from the right hand side x,y,z
                   # then unpack left hand side: z=1; y=1; z=1 (overwriting z)
print(x,y,z)

评论

0赞 alani 8/25/2020
请参阅阿伦·乌普雷蒂(Arun Upreti)提出的问题下的评论,询问其来源。由于您已经发布了带有答案的答案,我将让您对此做出回应:-)(1,1,2)
1赞 tdelaney 8/25/2020
@alani - 这也回答了第一个问题......但我会看看如何工作。
0赞 alani 8/25/2020
谢谢你。
-1赞 AriesNinja 8/25/2020 #3

在第 3 行,您将 z 设置为 y “x,y,z=x,x,y”

评论

0赞 Sebastian Simon 8/26/2020
问题是关于第二个,而不是第一个。你的答案没有解释.printz,y,z=x,y,z
0赞 AriesNinja 8/27/2020
这是因为由于您在元组中将 z 设置为 2 个值,因此它会自动将变量分配给第二个值,即它本身。
1赞 Mark Tolonen 8/25/2020 #4

Python 元组赋值使用堆栈,因此假设 x=1 且 y=2:

x,y,z=x,x,y

抽象地翻译为:

push x (value 1) on stack:    top_of_stack(TOS) -> 1
push x (value 1) on stack:    TOS -> 1, 1
push y (value 2) on stack:    TOS -> 2, 1, 1
reverse top 3 stack entries:  TOS -> 1, 1, 2
pop stack and store in x (x=1)  TOS -> 1, 2
pop stack and store in y (y=1)  TOS -> 2
pop stack and store in z (z=2)  TOS -> empty

最终结果是 x=1, y=1, z=2,下一行:

z,y,z=x,y,z

推 x,y,z (1,1,2),然后加载 z=1,然后 y=1,然后 z=2(覆盖 z=1)。

以下是带有注释的实际反汇编:

>>> dis.dis('x=1;y=2;x,y,z=x,x,y;z,y,z=x,y,z')
  1           0 LOAD_CONST               0 (1)     # load constant 1
              2 STORE_NAME               0 (x)     # assign to x
              4 LOAD_CONST               1 (2)     # load constant 2
              6 STORE_NAME               1 (y)     # assign to y
              8 LOAD_NAME                0 (x)     # push x on stack (1)
             10 LOAD_NAME                0 (x)     # push x again on stack (1)
             12 LOAD_NAME                1 (y)     # push y on stack (2)
             14 ROT_THREE                          # two instructions reverse stack
             16 ROT_TWO                            # .. 2,1,1 becomes 1,1,2
             18 STORE_NAME               0 (x)     # pop x=1
             20 STORE_NAME               1 (y)     # pop y=1
             22 STORE_NAME               2 (z)     # pop z=2
             24 LOAD_NAME                0 (x)     # push x (1)
             26 LOAD_NAME                1 (y)     # push y (1)
             28 LOAD_NAME                2 (z)     # push z (2)
             30 ROT_THREE                          # reverse stack
             32 ROT_TWO                            #  2,1,1 becomes 1,1,2
             34 STORE_NAME               2 (z)     # pop z=1  <---
             36 STORE_NAME               1 (y)     # pop y=1      \
             38 STORE_NAME               2 (z)     # pop z=2 (overwriting previous)

您也可以将其更抽象地理解为:

  1. 首先计算右侧值。
  2. 将从左到右分配给右侧的变量。

所以:

x=1
y=2
x,y,z=x,x,y

方法:

# x,y,z=1,1,2
x=1
y=1
z=2

然后:

z,y,z=x,y,z

方法:

# z,y,z = 1,1,2
z=1
y=1
z=2   # overwriting previous z=1

评论

0赞 Arun Upreti 8/25/2020
我从来不知道它使用堆栈实现。所以我弄错了。