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 · 6842 次点击
    这是一个创建于 2429 天前的主题,其中的信息可能已经有所发展或是发生改变。
    今天回答了一个主题, 一不小心进入了一个坑, 耗费了好多时间终于弄懂了
    我想要将 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++同等的让人懵逼的技能😒
    orangeade
        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   ·   实用小工具   ·   5176 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 40ms · UTC 03:56 · PVG 11:56 · LAX 19:56 · JFK 22:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.