Python 中的多个赋值和评估顺序

Multiple assignment and evaluation order in Python

提问人:Rafael Carrillo 提问时间:1/4/2012 最后编辑:CrazyChuckyRafael Carrillo 更新时间:5/17/2022 访问量:55170

问:

以下 Python 表达式之间有什么区别:

# First:

x,y = y,x+y

# Second:

x = y
y = x+y

First 给出的结果与 Second 不同的结果。

例如,

第一:

>>> x = 1
>>> y = 2
>>> x,y = y,x+y
>>> x
2
>>> y
3

第二:

>>> x = 1
>>> y = 2
>>> x = y
>>> y = x+y
>>> x
2
>>> y
4

y 是 3 在 First 和 4 在 Second

python 变量 运算符 多重赋值

评论


答:

1赞 DonCallisto 1/4/2012 #1

在第二种情况下,您将x+yx

在第一种情况下,第二个结果 () 被分配给x+yy

这就是为什么你得到不同的结果。

编辑后

发生这种情况是因为,在声明中

x,y = y,x+y

将计算右侧成员中的所有变量,然后将其存储在左侧成员中。因此,首先从右成员开始,然后从左成员开始。

在第二句话中

x = y
y = x + y

yo 首先评估并将其分配给 ;这样,总和等于总和,而不是第一种情况。yxx+yy+yx+x

1赞 Serdalis 1/4/2012 #2

第一个是类似元组的赋值:

x,y = y,x+y

其中 是元组的第一个元素,是第二个元素,因此您正在做的是:xy

x = y
y = x+y

第二个是做一个直接的分配:

x=y
x=x+y
8赞 Abhijit 1/4/2012 #3

第一种表达式:

  1. 创建具有值的临时元组y,x+y
  2. 分配给另一个临时元组
  3. 将元组提取为变量和xy

第二个语句实际上是两个表达式,没有元组用法。

令人惊讶的是,第一种表达方式实际上是:

temp=x
x=y
y=temp+y

您可以详细了解“括号形式”中逗号的用法。

115赞 Fred Foo 1/4/2012 #4

在赋值语句中,在实际设置变量之前,总是对右侧进行全面评估。所以

x, y = y, x + y

evalus (我们称之为结果 ), evalus (call that ),然后设置为 和 。也就是说,这就像yhamx + yspamxhamyspam

ham = y
spam = x + y
x = ham
y = spam

相比之下,

x = y
y = x + y

设置为 ,然后设置为 (which ) 加 ,所以它等价于xyyx== yy

x = y
y = y + y

评论

0赞 jxramos 9/18/2018
为了与代码库中的类似语法相关联,可能与 相同,因此括号是不必要的。这听起来对吗?x,y = y,x+y(x,y) = y,x+y
0赞 wjandrea 6/13/2020
@jxramos 是的,括号是不必要的,但这更像是一个关于元组的问题。
19赞 unutbu 1/4/2012 #5

在文档中标题为“评估顺序”的部分中对此进行了解释:

...在评估作业时,将评估右侧 在左侧之前。

0赞 li bing zhao 9/20/2017 #6
a, b = 0, 1
while b < 10:
    print(b)
    a, b = b, a+b

输出

1
1
2
3
5
8

变量 和 同时得到新值 和 ,相同,并同时赋值。ab01a, b = b, a+bab

0赞 Wizard 1/17/2018 #7

让我们来了解一下其中的区别。

x, y = y, x + y它是 x 元组 xssignment,mexns ,就像(x, y) = (y, x + y)(x, y) = (y, x)

来自 x 的 Stxrt 快速示例:

x, y = 0, 1
#equivxlent to
(x, y) = (0, 1)
#implement xs
x = 0
y = 1

当涉及到 ExFP 时,让 x 直接尝试(x, y) = (y, x + y)

x, y = 0, 1
x = y #x=y=1
y = x + y #y=1+1
#output
In [87]: x
Out[87]: 1
In [88]: y
Out[88]: 2

然而

In [93]: x, y = y, x+y
In [94]: x
Out[94]: 3
In [95]: y
Out[95]: 5

结果与第一次尝试不同。

谢谢,因为 Python 首先评估右手 所以它相当于:x+y

old_x = x
old_y = y
c = old_x + old_y
x = old_y
y = c

总之,意味着,
交换得到old_value,
交换得到旧价值和旧价值的总和,
x, y = y, x+yxyyxy

3赞 akinuri 2/13/2018 #8

我最近开始使用 Python,这个“功能”让我感到困惑。虽然给出了很多答案,但我还是会发表我的理解。

如果我想交换两个变量的值,在 JavaScipt 中,我会执行以下操作:

var a = 0;
var b = 1;

var temp = a;
a = b;
b = temp;

我需要第三个变量来临时保存其中一个值。一个非常直接的交换是行不通的,因为两个变量最终会得到相同的值。

var a = 0;
var b = 1;

a = b; // b = 1 => a = 1
b = a; // a = 1 => b = 1

想象一下,有两个不同的(红色和蓝色)桶,其中分别有两种不同的液体(水和油)。现在,尝试交换桶/液体(蓝色桶中的水和红色桶中的油)。除非你有额外的桶,否则你无法做到这一点。

Python 使用一种“更干净”的方式/解决方案来处理这个问题:元组赋值

a = 0
b = 1

print(a, b) # 0 1

# temp = a
# a = b
# b = temp

a, b = b, a # values are swapped

print(a, b) # 1 0

我想,通过这种方式,Python 会自动创建“temp”变量,我们不必担心它们。

评论

0赞 Harsh Goyal 7/31/2019
就像链接提到的那样,“在任何赋值之前,都会对右侧的所有表达式进行评估”。谢谢你的澄清。
2赞 wjandrea 6/13/2020 #9

其他答案已经解释了它是如何工作的,但我想添加一个非常具体的例子。

x = 1
y = 2
x, y = y, x+y

在最后一行中,首先取消引用名称,如下所示:

x, y = 2, 1+2

然后计算表达式:

x, y = 2, 3

然后展开元组,然后进行赋值,相当于:

x = 2; y = 3
5赞 Zuzu Corneliu 6/22/2020 #10

关于左侧的观察结果:分配的顺序保证是它们出现的顺序,换句话说:

a, b = c, d

在功能上等同于精确(除了 t 创建):

t = (c, d)
a = t[0] # done before 'b' assignment
b = t[1] # done after 'a' assignment

这在对象属性赋值等情况下很重要,例如:

class dummy:
    def __init__(self): self.x = 0

a = dummy(); a_save = a
a.x, a = 5, dummy()
print(a_save.x, a.x) # prints "5 0" because above is equivalent to "a = dummy(); a_save = a; t = (5, dummy()); a.x = t[0]; a = t[1]"

a = dummy(); a_save = a
a, a.x = dummy(), 5
print(a_save.x, a.x) # prints "0 5" because above is equivalent to "a = dummy(); a_save = a; t = (dummy(), 5); a = t[0]; a.x = t[1]"

这也意味着您可以使用单行代码来执行对象创建和访问等操作,例如:

class dummy:
    def __init__(self): self.x = 0
# Create a = dummy() and assign 5 to a.x
a, a.x = dummy(), 5
1赞 Angela C 11/24/2020 #11

对于新手,我遇到了这个可以帮助解释这一点的例子:

# Fibonacci series:
# the sum of two elements defines the next
a, b = 0, 1
while a < 10:
    print(a)
    a, b = b, a+b

使用多重赋值时,将初始值设置为 a=0、b=1。 在 while 循环中,两个元素都被分配了新值(因此称为“多重”赋值)。将其视为 (a,b) = (b,a+b)。所以 a = b, b = a+b 在循环的每次迭代中。这在 a<10 时继续。

结果: 0 1 1 2 3 5 8