我知道tuple unpacking,但是如果你在一行上有多个等号,那么这个赋值是什么? la a = b = True
特别是当RHS可变时,它总是让我感到沮丧,但我在找到正确的关键词以便在文档中搜索时遇到了麻烦。
答案 0 :(得分:44)
这是一系列作业,用于描述它的术语是......
- 我可以获得鼓号吗?
我只是给了它一个很好的谷歌运行,并发现没有那么多关于这个主题的阅读,可能是因为大多数人发现它非常直接使用(只有真正的极客想知道更多关于主题)。
在上一个表达式中,评估顺序可以被视为从最右边的=
开始,然后向左移动,这相当于写作:
b = True
a = b
上面的顺序是大多数语言描述赋值链的顺序,但是python以不同的方式表达。在python中,表达式被评估为下面的等价物,但它不会产生任何其他结果,而不是之前描述的结果。
temporary_expr_result = True
a = temporary_expr_result
b = temporary_expr_result
此处有关stackoverflow的更多信息:
答案 1 :(得分:6)
好的,“链式任务”是我追求的搜索词,但经过一些挖掘后我认为这不是严格正确的。但搜索比“转让声明的特殊情况”更容易。
The Wikipedia article senderle链接说:
在Python中,赋值语句不是表达式,因此不是 返回一个值。相反,链式作业是一系列的 具有单个表达式的多个目标的语句。该 分配从左到右执行,以便
i = arr[i] = f()
计算表达式f()
,然后将结果分配给最左边 target,i
,然后将相同的结果分配给下一个目标,arr[i]
,使用新值i
。
另一位blog post说:
在Python中,赋值语句不返回值。链式 赋值(或更准确地说,代码看起来像链式赋值 声明)作为特殊情况得到承认和支持 转让声明。
这对我来说是最正确的,仔细阅读the docs - 特别是(target_list "=")+
- 这也说明了
赋值语句计算表达式列表...并分配 每个目标列表的单个结果对象,从左到右 右。
所以它并非真正“从最左边到最左边进行评估” - 对RHS进行评估,然后从最左边的目标分配到右边 - 而不是我能想到任何真实世界(甚至是人为的)的例子。会有所作为。
答案 2 :(得分:5)
dis
(反汇编)模块,此输出进一步支持@refp的答案:
>>> def a(x):
... g = h = x
...
>>> import dis
>>> dis.dis(a)
2 0 LOAD_FAST 0 (x)
3 DUP_TOP
4 STORE_FAST 1 (g)
7 STORE_FAST 2 (h)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
检索并复制RHS,然后从左到右存储到目标变量中(使用e = f = g = h = x
自行尝试)。
如果RHS是一个函数调用,其他一些海报就被混淆了,比如a = b = fn()
- RHS只被评估一次,然后结果分配给每个连续变量。如果返回的值是可变的,如列表或字典,则可能导致不需要的共享。
对于那些使用threading
的人来说,注意到链式赋值形式在多个显式赋值语句中没有“原子性”是有用的 - 在g和h的赋值之间可能发生线程切换,并且查看其中两个变量的另一个线程可以在两个变量中看到不同的值。
来自documentation, 7.2. Assignment statements,g
和h
是两个目标列表,x
是表达式列表 :
assignment_stmt ::= (target_list "=")+ (expression_list | yield_expression)
赋值语句计算表达式列表(请记住,这可以是单个表达式或以逗号分隔的列表,后者产生元组)并将单个结果对象分配给每个目标列表,从左到右。
答案 3 :(得分:3)
if l1.val <= l2.val:
tail = tail.next = l1 # this line
l1 = l1.next
我所期待的是
tail.next = l1
tail = tail.next
# or equivalently
# tail = l1
而我在下面,在列表中产生一个自循环,让我陷入无休止的循环,呐喊......
tail = l1
tail.next = l1 # now l1.next is changed to l1 itself
因为a = b = c, 单向(python,例如)等效于
tmp = evaluate(c)
evaluate(a) = tmp
evaluate(b) = tmp
并且两个赋值具有相等的右操作数。
另一个(例如C ++)等同于
evaluate(b) = evaluate(c)
evaluate(a) = evaluate(b)
因为在这种情况下a = b = c
基本上是
b = c
a = b
和两个右手操作数可能不同。
为什么类似的代码在C ++中运行良好。