首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >单行Python多个赋值语句

单行Python多个赋值语句
EN

Stack Overflow用户
提问于 2015-08-22 13:09:59
回答 5查看 29.3K关注 0票数 47

(别担心,这不是解压元组的另一个问题。)

在python中,像foo = bar = baz = 5这样的语句将变量foo、bar和baz分配给5。

代码语言:javascript
复制
>>> foo[0] = foo = [0]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'foo' is not defined
>>> foo = foo[0] = [0]
>>> foo
[[...]]
>>> foo[0]
[[...]]
>>> foo is foo[0]
True

但是python语言引用声明赋值语句具有以下形式

代码语言:javascript
复制
(target_list "=")+ (expression_list | yield_expression)

在赋值时,首先对expression_list进行评估,然后进行赋值。

那么,既然foo = bar = 5不是expression_list,那么行expression_list怎么会是有效的呢?如何对一行中的多个作业进行分析和评估?我看错了语言参考资料吗?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2015-08-22 16:09:23

所有的功劳都归功于@MarkDickinson,他在评论中回答了这一点:

注意+中的(target_list "=")+,这意味着一个或多个副本。在foo = bar = 5中,有两个(target_list "=")产品,而expression_list部分只是5

在赋值语句中,赋值语句中的所有target_list产品(即类似于foo =的东西)在对expression_list进行计算之后,都会从左到右分配给语句右侧的expression_list

当然,通常的‘元组-解包’赋值语法在这个语法中工作,允许您做以下事情

代码语言:javascript
复制
>>> foo, boo, moo = boo[0], moo[0], foo[0] = moo[0], foo[0], boo[0] = [0], [0], [0]
>>> foo
[[[[...]]]]
>>> foo[0] is boo
True
>>> foo[0][0] is moo
True
>>> foo[0][0][0] is foo
True
票数 28
EN

Stack Overflow用户

发布于 2015-08-22 14:25:53

Mark解释了正在发生的事情的语法,但是涉及foo的奇怪例子表明语义可能是违反直觉的。

在C中,=是一个右关联运算符,它作为赋值的RHS返回值,所以当您编写x = y = 5时,首先计算y=5 (在过程中将5赋值给y ),然后将这个值(5)赋值给x

在我阅读这个问题之前,我天真地假设Python中发生了大致相同的事情。但是,在Python中,=不是表达式(例如,2 + (x = 5)是语法错误)。因此Python必须以另一种方式实现多个任务。

我们可以拆解而不是猜测:

代码语言:javascript
复制
>>> import dis
>>> dis.dis('x = y = 5')
  1           0 LOAD_CONST               0 (5)
              3 DUP_TOP
              4 STORE_NAME               0 (x)
              7 STORE_NAME               1 (y)
             10 LOAD_CONST               1 (None)
             13 RETURN_VALUE

有关字节码指令的说明,请参见

第一条指令将5推到堆栈上。

第二个指令重复它--所以现在堆栈的顶部有两个5s。

根据字节码文档,STORE_NAME(name)“实现名称= TOS”

因此,STORE_Name(x)实现x = 5 (堆栈顶部的5),在堆栈上弹出5,然后STORE_Name(y)与堆栈上的其他5一起实现y = 5

其余的字节码在这里并不直接相关。

foo = foo[0] = [0]的例子中,由于列表的存在,字节代码更加复杂,但其结构基本相同。关键的观察是,一旦列表[0]被创建并放在堆栈上,那么指令DUP_TOP就不会在堆栈上放置[0]的另一个副本,而是放置对列表的另一个引用。换句话说,在那个阶段,堆栈的前两个元素是同一个列表的别名。在比较简单的情况下,可以最清楚地看出这一点:

代码语言:javascript
复制
>>> x = y = [0]
>>> x[0] = 5
>>> y[0]
5

执行foo = foo[0] = [0]时,首先将列表[0]分配给foo,然后将同一个列表的别名分配给foo[0]。这就是为什么它导致foo是一个循环引用。

票数 24
EN

Stack Overflow用户

发布于 2015-08-22 16:24:42

stmt

赋值语句计算表达式列表(请记住,这可以是一个表达式或逗号分隔的列表,后者生成一个元组),并将单个结果对象从左到右分配给每个目标列表。

票数 10
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32156515

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档