首页 > 代码库 > python链式赋值有哪些注意事项?

python链式赋值有哪些注意事项?

在我们在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 的值: 3
的值: [3, 2, 3, 4, 5, 6]
然而这个答案只是对了一半因为s的值错了有兴趣的朋友可以自行上机试下正确答案是:
i 的值: 3
的值: [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

python链式赋值有哪些注意事项?