Python中的多重赋值和评估顺序
Posted
技术标签:
【中文标题】Python中的多重赋值和评估顺序【英文标题】:Multiple assignment and evaluation order in Python 【发布时间】:2012-02-02 06:49:00 【问题描述】:以下 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 是 First 中的 3 和 Second 中的 4
【问题讨论】:
【参考方案1】:在赋值语句中,总是在进行变量的实际设置之前完全评估右侧。所以,
x, y = y, x + y
评估y
(我们称结果为ham
),评估x + y
(称其为spam
),然后将x
设置为ham
和y
spam
。也就是说,就像
ham = y
spam = x + y
x = ham
y = spam
相比之下,
x = y
y = x + y
将x
设置为y
,然后将y
设置为x
(== y
)加上y
,所以它相当于
x = y
y = y + y
【讨论】:
为了与代码库中可能发现的类似语法相关,x,y = y,x+y
与 (x,y) = y,x+y
相同,因此括号是不必要的。听起来对吗?
@jxramos 是的,括号是不必要的,但这更多是关于元组的问题。【参考方案2】:
在标题为"Evaluation order"的部分的文档中进行了解释:
...在评估分配时,评估右侧 在左侧之前。
【讨论】:
【参考方案3】:第一个表达式:
-
创建一个临时元组,其值为
y,x+y
分配到另一个临时元组
将元组提取到变量x
和y
第二条语句实际上是两个表达式,没有元组的用法。
惊喜的是,第一个表达式居然是:
temp=x
x=y
y=temp+y
您可以在“Parenthesized forms”中了解更多关于逗号的用法。
【讨论】:
【参考方案4】:我最近开始使用 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 用一种“更干净”的方式/解决方案来处理这个问题:Tuple Assignment。
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 会自动创建“临时”变量,我们不必担心它们。
【讨论】:
就像链接中提到的“右侧的所有表达式都在任何分配之前进行评估”。感谢您的澄清。【参考方案5】:关于左侧的观察:分配的顺序保证是它们出现的顺序,换句话说:
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
【讨论】:
【参考方案6】:在第二种情况下,您将x+y
分配给x
第一种情况,第二个结果(x+y
)赋值给y
这就是您获得不同结果的原因。
修改后
发生这种情况是因为,在声明中
x,y = y,x+y
右侧成员的所有变量都被评估,然后存储在左侧成员中。所以first继续处理右边的成员,second处理左边的成员。
在第二个语句中
x = y
y = x + y
你首先评估y
并将其分配给x
;这样,x+y
的总和等于 y+y
的总和,而不是 x+x
的总和,这是第一种情况。
【讨论】:
【参考方案7】:第一个是类似元组的赋值:
x,y = y,x+y
其中x
是元组的第一个元素,y
是第二个元素,因此您要做的是:
x = y
y = x+y
而第二个是直接分配:
x=y
x=x+y
【讨论】:
【参考方案8】:其他答案已经解释了它是如何工作的,但我想添加一个非常具体的例子。
x = 1
y = 2
x, y = y, x+y
在最后一行中,首先像这样取消引用名称:
x, y = 2, 1+2
然后计算表达式:
x, y = 2, 3
然后元组展开,然后发生赋值,相当于:
x = 2; y = 3
【讨论】:
【参考方案9】:对于新手,我遇到了一个可以帮助解释这一点的示例:
# 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。这将继续,而
结果: 0 1 1 2 3 5 8
【讨论】:
【参考方案10】:让我们了解一下不同之处。
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
当谈到(x, y) = (y, x + y)
ExFP,让x直接试试
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
综上,x, y = y, x+y
的意思是,x
交换得到y
的old_value,y
交换得到旧值x
和旧值y
之和,
【讨论】:
【参考方案11】:a, b = 0, 1
while b < 10:
print(b)
a, b = b, a+b
输出
1
1
2
3
5
8
变量a
和b
同时得到新值0
和1
,同样的a, b = b, a+b
、a
和b
被同时赋值。
【讨论】:
以上是关于Python中的多重赋值和评估顺序的主要内容,如果未能解决你的问题,请参考以下文章
Multiindex Pandas Dataframe中的多重赋值[重复]