在我們在python
開發(fā)
http://www.maiziedu.com/land/python/中,
經(jīng)常遇到賦值語句
,
就像下面的那樣
:
a = 3b = 3
可能你會覺得我又要說什么變量賦值就是引用,
這么簡單的知識就不討論啦
,
相信聰明的大家肯定都知道的
, 本文和大家分享的是
鏈式賦值相關(guān)內(nèi)容,一起來看看吧,希望對大家學習和使用這部分內(nèi)容有所幫助。
先科普下什么是
鏈式賦值 :
鏈式賦值:
同時對幾個變量進行賦值
例如:
a = b = c = 3
好了,
現(xiàn)在正式進入正題
:
>>> 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
第一列的數(shù)字,
代表中間的
字節(jié)碼
是屬于哪一行代碼的.
第1~2
行簡單解釋下
:
分別
LOAD_CONST 5
個數(shù)字
,
組成一個列表
,
賦值給
s,
再取一個
0,
賦值給
i.
接下來的就是我們關(guān)心的
,
也是帶給我們意外的代碼
.
第3
行
:
LOAD_CONST
取出常量3,
它并不是像上面執(zhí)行
STORE_NAME ,
而是采用
DUP_TOP ,
這是什么鬼
,
我們這要去看下這指令具體是干嘛的
:
//
取自
python/ceval.c
PyEval_EvalFrameEx(PyFrameObject *f,
int throwflag)
{
... (
省略
)
TARGET_NOARG(DUP_TOP)
{
v = TOP(); //
復制運行棧幀的頂部值
Py_INCREF(v); //
增加引用計數(shù)
PUSH(v); //
再壓入運行棧幀
FAST_DISPATCH();
}
... (
省略
)
}
DUP_TOP
指令說白了,
就是將剛才
LOAD_CONST
指令取出的常量3,
復制一份給
v,
然后再壓回去運行棧幀
,
這樣就有兩個
3
了
,
為什么要這么做
,
肯呢個大家已經(jīng)猜到了
,
不過我們還是得繼續(xù)看具體是不是像我們想的那樣
,
繼續(xù)看會字節(jié)碼
:
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
的元素
,
具體的源碼就不再看
,
到這就夠了
.
所以看到這,
相信大家都能清楚
,
為什么結(jié)果是
[1, 2, 3, 3, 5, 6]
這跟我們想象中的鏈式賦值很不同,
我們以前總是覺得
,
賦值要從右到左依次執(zhí)行
,
先執(zhí)行
s = 3 ,
再執(zhí)行
i=3 ,
然而這些是類似
c語言
這類支持表達式賦值才允許的.
在
c語言
中,
s = 3
表達式是有返回值的.
它會返回賦值的結(jié)果
3,
所以在它們的
鏈式賦值
中,
是將右邊表達式的返回值
,
再賦值給左邊的
,
例如
:
a = s = 3
等價于:
a = (s = 3)
也就是 s=3
返回
3,
再賦值給
a
而在
python
是不支持這種表達式賦值的,
也就是表達式是沒有返回值的
,
如果硬要
a = (s = 3)
只會觸發(fā)
SyntaxError: invalid syntax
希望大家以后在用到這種鏈式賦值時,
盡量避免這些問題哦
來源:SegmentFault