为什么链式作业以这种方式工作?

时间:2018-02-06 01:06:36

标签: python python-3.x python-2.7

我在文章中找到了作业a = a[1:] = [2]。我在python3和python2中尝试过它;这一切都有效,但我不明白它是如何工作的 =这里不像C; C从右到左处理=。 python如何处理=运算符?

2 个答案:

答案 0 :(得分:15)

the language docs on assignment

  

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

在这种情况下,a = a[1:] = [2]有一个表达式列表[2],以及两个"目标列表",aa[1:],其中{{1}是最左边的"目标列表"。

您可以通过查看反汇编来了解其行为:

a

(可以忽略反汇编的最后两行,>>> import dis >>> dis.dis('a = a[1:] = [2]') 1 0 LOAD_CONST 0 (2) 2 BUILD_LIST 1 4 DUP_TOP 6 STORE_NAME 0 (a) 8 LOAD_NAME 0 (a) 10 LOAD_CONST 1 (1) 12 LOAD_CONST 2 (None) 14 BUILD_SLICE 2 16 STORE_SUBSCR 18 LOAD_CONST 2 (None) 20 RETURN_VALUE 正在使函数包装器反汇编字符串)

需要注意的重要一点是,当您执行dis时,x = y = some_val会加载到堆栈上(在本例中由some_valLOAD_CONST加载),然后堆栈条目被复制并从左到右分配给给定的目标。

所以当你这样做时:

BUILD_LIST

它引用了对包含a = a[1:] = [2] 的全新list的两个引用,第一个操作是2STORE的引用之一。a。接下来,它将第二个引用存储到a[1:],但由于切片分配会改变a本身,因此必须再次加载a,这样才能获得刚存储的list。幸运的是,list可以抵御自我切片分配,或者我们遇到问题(它会永远读取它刚添加的值,直到我们内存不足并崩溃为止);因此,它表现为[2]的副本被指定为从索引1开始替换任何和所有元素。

最终结果相当于你完成了:

_ = [2]
a = _
a[1:] = _

但它避免使用_名称。

要清楚,反汇编注释:

列表[2]

  1           0 LOAD_CONST               0 (2)
              2 BUILD_LIST               1

复制[2]的参考:

              4 DUP_TOP

执行商店到a

              6 STORE_NAME               0 (a)

执行商店到a[1:]

              8 LOAD_NAME                0 (a)
             10 LOAD_CONST               1 (1)
             12 LOAD_CONST               2 (None)
             14 BUILD_SLICE              2
             16 STORE_SUBSCR

答案 1 :(得分:7)

我理解这些作业的方式是,这相当于

temp = [2]
a = temp
a[1:] = temp

[2, 2]的结果值与此解释一致。