赞
踩
Mark Dickinson解释了正在发生的事情的语法,但是涉及foo的奇怪例子表明,语义可能是反直觉的。
在C中,=是一个右关联运算符,它返回赋值的RHS值,因此当您编写x = y = 5时,首先对y=5求值(在进程中将5赋值给y),然后将该值(5)赋值给x。
在阅读这个问题之前,我天真地假设在Python中会发生大致相同的事情。但是,在Python中,=不是表达式(例如,2 + (x = 5)是语法错误)。所以Python必须以另一种方式实现多个赋值。
我们可以分解而不是猜测:>>> 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
有关字节码指令的说明,请参见this。
第一条指令将5推送到堆栈上。
第二条指令复制了它——所以现在堆栈的顶部有两个5s
STORE_NAME(name)“根据字节码文档实现name=TOS”
因此STORE_Name(x)实现x = 5(堆栈顶部的5个),在它运行时弹出堆栈中的5,然后STORE_Name(y)实现y = 5和堆栈中的其他5个。
其余的字节码在这里并不直接相关。
在foo = foo[0] = [0]的情况下,由于列表的原因,字节码更加复杂,但是具有基本相似的结构。关键的观察是,一旦创建了列表[0]并将其放在堆栈上,那么指令DUP_TOP就不会在堆栈上放置[0]的另一个副本,而是将另一个引用放在列表上。换句话说,在该阶段,堆栈的前两个元素是同一列表的别名。这在更简单的情况下可以看得更清楚:>>> x = y = [0]
>>> x[0] = 5
>>> y[0]
5
当执行foo = foo[0] = [0]时,首先将列表[0]分配给foo,然后将同一列表的别名分配给foo[0]。这就是它导致foo成为循环引用的原因。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。