麦子学院 2017-05-13 13:40
python链式赋值有哪些注意事项?
回复:0 查看:2263
在我们在python
开发
http://www.maiziedu.com/land/python/中,
经常遇到赋值语句
,
就像下面的那样
:
a = 3b = 3
可能你会觉得我又要说什么变量赋值就是引用,
这么简单的知识就不讨论啦
,
相信聪明的大家肯定都知道的
, 本文和大家分享的是
链式赋值相关内容,一起来看看吧,希望对大家学习和使用这部分内容有所帮助。
先科普下什么是
链式赋值 :
链式赋值:
同时对几个变量进行赋值
例如:
a = b = c = 3
好了,
现在正式进入正题
:
>>> s = [1, 2, 3, 4, 5, 6]>>> i = 0>>> i = s = 3
i
和
s
的值分别是什么
?
可能大家一眼看下去
,
就能得出答案
:
i
的值: 3
s
的值
: [3, 2, 3, 4, 5, 6]
然而,
这个答案只是对了一半
,
因为
s
的值错了
!
有兴趣的朋友可以自行上机试下
,
正确答案是
:
i
的值: 3
s
的值
: [1, 2, 3, 3, 5, 6]
s
的列表
,
并没有像我们想象中的那样
,
就
i=0
位置上的元素,
变成
3,
而是将
i=3
位置的元素改成3
了
,
为什么会这样
?
一起来解析下吧
,
上
dis
大杀器!
[
root@iZ23pynfq19Z ~]# cat 2.py
s = [
1, 2, 3, 4, 5]
i = 0
g = i = s[
i] = 3
[
root@iZ23pynfq19Z ~]# python -m dis 2.py
1 0 LOAD_CONST 0 (
1)
3 LOAD_CONST 1 (
2)
6 LOAD_CONST 2 (
3)
9 LOAD_CONST 3 (
4)
12 LOAD_CONST 4 (
5)
15 BUILD_LIST 5
18 STORE_NAME 0 (
s)
2 21 LOAD_CONST 5 (
0)
24 STORE_NAME 1 (
i)
3 27 LOAD_CONST 2 (
3)
30 DUP_TOP
31 STORE_NAME 2 (
g)
34 DUP_TOP
35 STORE_NAME 1 (
i)
38 LOAD_NAME 0 (
s)
41 LOAD_NAME 1 (
i)
44 STORE_SUBSCR
45 LOAD_CONST 6 (
None)
48 RETURN_VALUE
第一列的数字,
代表中间的
字节码
是属于哪一行代码的.
第1~2
行简单解释下
:
分别
LOAD_CONST 5
个数字
,
组成一个列表
,
赋值给
s,
再取一个
0,
赋值给
i.
接下来的就是我们关心的
,
也是带给我们意外的代码
.
第3
行
:
LOAD_CONST
取出常量3,
它并不是像上面执行
STORE_NAME ,
而是采用
DUP_TOP ,
这是什么鬼
,
我们这要去看下这指令具体是干嘛的
:
//
取自
python/ceval.c
PyEval_EvalFrameEx(PyFrameObject *f,
int throwflag)
{
... (
省略
)
TARGET_NOARG(DUP_TOP)
{
v = TOP(); //
复制运行栈帧的顶部值
Py_INCREF(v); //
增加引用计数
PUSH(v); //
再压入运行栈帧
FAST_DISPATCH();
}
... (
省略
)
}
DUP_TOP
指令说白了,
就是将刚才
LOAD_CONST
指令取出的常量3,
复制一份给
v,
然后再压回去运行栈帧
,
这样就有两个
3
了
,
为什么要这么做
,
肯呢个大家已经猜到了
,
不过我们还是得继续看具体是不是像我们想的那样
,
继续看会字节码
:
35 STORE_NAME 1 (
i)
38 LOAD_NAME 0 (
s)
41 LOAD_NAME 1 (
i)
44 STORE_SUBSCR
果然不出我们所料,
开始将这些
3
通过
STORE_NAME
赋值给i,
而对于
s,
它反而是
,
再一次
LOAD_NAME
取出i
的值
,
此时
i
的值是
3,
不是一开始的
0
了
,
在通过
STORE_SUBSCR
指令,
将刚才压入运行时时栈的
3
赋值给位置是
3
的元素
,
具体的源码就不再看
,
到这就够了
.
所以看到这,
相信大家都能清楚
,
为什么结果是
[1, 2, 3, 3, 5, 6]
这跟我们想象中的链式赋值很不同,
我们以前总是觉得
,
赋值要从右到左依次执行
,
先执行
s = 3 ,
再执行
i=3 ,
然而这些是类似
c语言
这类支持表达式赋值才允许的.
在
c语言
中,
s = 3
表达式是有返回值的.
它会返回赋值的结果
3,
所以在它们的
链式赋值
中,
是将右边表达式的返回值
,
再赋值给左边的
,
例如
:
a = s = 3
等价于:
a = (s = 3)
也就是 s=3
返回
3,
再赋值给
a
而在
python
是不支持这种表达式赋值的,
也就是表达式是没有返回值的
,
如果硬要
a = (s = 3)
只会触发
SyntaxError: invalid syntax
希望大家以后在用到这种链式赋值时,
尽量避免这些问题哦
来源:SegmentFault