Python 的赋值坑 , a=b=c=1??? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
careofzm
V2EX    Python

Python 的赋值坑 , a=b=c=1???

  •  
  •   careofzm 2018-04-01 17:17:39 +08:00 7238 次点击
    这是一个创建于 2752 天前的主题,其中的信息可能已经有所发展或是发生改变。
    今天回答了一个主题, 一不小心进入了一个坑, 耗费了好多时间终于弄懂了
    我想要将 a,b,c 变量同时赋值 1, 我使用了
    ```
    In [192]: a = b = c = 1

    In [193]: a, b, c
    Out[193]: (1, 1, 1)
    ```
    很明显我赋值成功了,a、b、c 都是 1
    但是这个下赋值顺序是怎么样的
    首先让我们先猜测一下:
    第一种方式:a,b,c 同时赋值 1,a=1, b=1, c=1
    第二种方式:依次赋值 c=1, b=c, a=b
    以上两种显然是很合理的
    但是我们要验证一下:
    于是我开始说到我遇到的坑(其实这个是在说明 list 的 append 添加方法为什么返回的是 None 出现的)
    假如我们创建变量 L 赋值为空, 我们先 L 以切片的形式添加 x 值
    ```
    In [200]: L = []

    In [201]: x = 4

    In [202]: L[len(L):] = [x]

    In [203]: L
    Out[203]: [4]
    ```
    我已经添加成功
    由于 Python 的引用原理,我们可以多次添加
    于是我想多次添加:
    ```
    In [206]: L = []

    In [207]: L[len(L):]=L[len(L):] = [x]

    In [208]: L
    Out[208]: [4, 4]

    ```
    如我所料的一样我成功添加了 2 个 4, 也是说我每次都能获得 4,并向 L 尾部相加, 可以确定是第一种方式, 因为第二种根本只能加进一个 4:
    第一种:L[len(L):]= [x], L[len(L):]= [x]
    第二种:L[len(L):]= [x],L[len(L):]= L[len(L):]

    好下面重点来了,我然后重点来了, 我又写了一个语句
    ```
    In [209]: L = []

    In [210]: L = L[len(L):]=L[len(L):] = [x]

    In [211]: L
    Out[211]: [4, 4, 4, 4]
    ```
    这个不对啊
    L 不应该等于[4]或者[4, 4, 4]吗,为什么会预测出两个结果,这个是赋值顺序问题, 正序和逆序
    第一种方式的两种顺序:
    正序:L = [x], L[len(L):] = [x], L[len(L):] = [x] L=[4,4,4]
    逆序:L[len(L):] = [x],L[len(L):] = [x],L=[x] L=[4]

    但是为什么会出现[4, 4, 4,4]
    唯一的解释便是第三种赋值方式:
    L = [x] # L = [4]
    L[len(L):]=L # L=[4,4]
    L[len(L):]=L # L=[4, 4, 4, 4]
    这样我们就完全解释了这种状况
    所以针对 a=b=c=1 这种赋值方式,其实是 a=1, b=a, c=a
    8 条回复    2018-04-02 21:37:14 +08:00
    xiaofengchen
        1
    xiaofengchen  
       2018-04-01 17:36:42 +08:00 via Android
    所以平时工作我们应该分开赋值,或者加括号?
    yianing
        2
    yianing  
       2018-04-01 17:39:55 +08:00
    恭喜 python 获得了和 c++同等的让人懵逼的技能
    orageade
        3
    orangeade  
       2018-04-01 18:48:49 +08:00 via Android
    用 id(a) 命令看一下
    dickmrbean
        4
    dickmrbean  
       2018-04-01 20:41:21 +08:00   11
    In [1]: import dis

    In [2]: dis.dis("a=b=c=1")
    1 0 LOAD_CONST 0 (1)
    2 DUP_TOP
    4 STORE_NAME 0 (a)
    6 DUP_TOP
    8 STORE_NAME 1 (b)
    10 STORE_NAME 2 (c)
    12 LOAD_CONST 1 (None)
    14 RETURN_VALUE
    tkmiles
        5
    tkmiles  
       2018-04-02 12:35:53 +08:00
    1. 首先, 你发现没有, 就算你不先赋值 L, 也可以直接运行语句 L = L[len(L):]=L[len(L):] = [x]!!! 这说明了, python 是先赋值 L, 剩下的就很好理解了

    2. 先赋值 L, 有 L=[4], 然后后一个 len 赋值, 有 L[len(L):]=L, 就是 L[1:] = L, 也就是 L[1:] = [4], 所以 L=[4, 4]

    3. 然后第一个 len 赋值, 有 L[len[L]:] = L, L[2:] = L, L[2:]=[4, 4], 所以 L=[4, 4, 4, 4]

    4. 看一下 dis

    In [3]: dis.dis("L = L[len(L):]=L[len(L):] = [x]")
    1 0 LOAD_NAME 0 (x)
    2 BUILD_LIST 1
    4 DUP_TOP
    6 STORE_NAME 1 (L)
    8 DUP_TOP
    10 LOAD_NAME 1 (L)
    12 LOAD_NAME 2 (len)
    14 LOAD_NAME 1 (L)
    16 CALL_FUNCTION 1
    18 LOAD_CONST 0 (None)
    20 BUILD_SLICE 2
    22 STORE_SUBSCR
    24 LOAD_NAME 1 (L)
    26 LOAD_NAME 2 (len)
    28 LOAD_NAME 1 (L)
    30 CALL_FUNCTION 1
    32 LOAD_CONST 0 (None)
    34 BUILD_SLICE 2
    36 STORE_SUBSCR
    38 LOAD_CONST 0 (None)
    40 RETURN_VALUE

    发现确实是先 BUILD_LIST, 然后 STORE_NAME 到 L 上, 然后后面的 STORE_SUBSCR 得去 debug 一下 python 的 C 代码了, 我 debug 下来发现, STORE_SUBSCR 赋值的时候, 赋值的对象确实是 L 自己, 也就是说 L[len(L):] = L, 这是因为之前赋值了 L = [4]之后, python 就直接用 L 作为等号右边的符号了.
    ggarlic
        6
    ggarlic  
       2018-04-02 14:04:21 +08:00
    恩,python 的赋值运算符是右结合的
    Sapp
        7
    Sapp  
       2018-04-02 14:57:47 +08:00
    js 还有个更坑的,a = { b : 1}, a.c = a = { d: 1} // a.c undefined,这毛病一直到 es6 的 let 才给解决。
    KingHL
        8
    KingHL  
       2018-04-02 21:37:14 +08:00
    好好的 python,非要被你这样用。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3692 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 47ms UTC 05:06 PVG 13:06 LAX 22:06 JFK 01:06
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86