i = i +1 写成 i += 1 有什么好处? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python he 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
terence4444
V2EX    Python

i = i +1 写成 i += 1 有什么好处?

  •  2
     
  •   terence4444 2016 年 5 月 8 日 18471 次点击
    这是一个创建于 3534 天前的主题,其中的信息可能已经有所发展或是发生改变。
    PyCharm 推荐写成后者,这样写跑起来比较快?
    50 条回复    2016-08-28 22:26:40 +08:00
    Shura
        1
    Shura  
       2016 年 5 月 8 日 via Android
    写着方便啊,而且如果要改变量名,只要改一次
    techme
        2
    techme  
       2016 年 5 月 8 日
    少打一个字符
    SkyEcho
        3
    SkyEcho  
       2016 年 5 月 8 日 via Android
    @Shura 用 ide 的重构变量名应该是最准确的,直接替换有时候会出错
    SkyEcho
        4
    SkyEcho  
       2016 年 5 月 8 日 via Android
    可能是编译器会有特殊处理吧
    hxtheone
        5
    hxtheone  
       2016 年 5 月 8 日
    会不会是前者计算出右值后会存入一个临时变量然后赋给左侧的 i, 而后者是在 i 本身上做计算, 所以效率会有一点点提升?

    个人猜测, 不对请轻喷
    chunqiuyiyu
        6
    chunqiuyiyu  
       2016 年 5 月 8 日
    少打一个字 提升效率 节约生命
    kalintw
        7
    kalintw  
       2016 年 5 月 8 日
    可以显示出 PyCharm 的存在感。哈哈。
    crab
        8
    crab  
       2016 年 5 月 8 日
    一样吧。和大括号另外一行
    jsonline
        10
    jsonline  
       2016 年 5 月 8 日
    你为什么要发帖
    junnplus
        11
    junnplus  
       2016 年 5 月 8 日   4
    In [4]: dis.dis('i = 0; i += 1')
    ....0 LOAD_CONST.... 0 (0)
    ....3 STORE_NAME....0 (i)
    ....6 LOAD_NAME....0 (i)
    ....9 LOAD_CONST....1 (1)
    ....12 INPLACE_ADD
    ....13 STORE_NAME....0 (i)
    ....16 LOAD_CONST....2 (None)
    ....19 RETURN_VALUE

    In [5]: dis.dis('i = 0; i = i + 1')
    ....0 LOAD_CONST....0 (0)
    ....3 STORE_NAME....0 (i)
    ....6 LOAD_NAME....0 (i)
    ....9 LOAD_CONST....1 (1)
    ....12 BINARY_ADD
    ....13 STORE_NAME....0 (i)
    ....16 LOAD_CONST....2 (None)
    ....19 RETURN_VALUE


    可以看出来,两者的区别只在 INPLACE_ADD 和 BINARY_ADD 上面
    terence4444
        12
    terence4444  
    OP
       2016 年 5 月 8 日
    @junnplus 这是 stackoverflow 的站内搜索?搜索引擎对符号搜索视而不见……
    liuhaotian
        13
    liuhaotian  
       2016 年 5 月 8 日 via iPhone
    只有 i++才有效率的提高因为可以直接 INC X
    junnplus
        14
    junnplus  
       2016 年 5 月 8 日
    @terence4444 并不会视而不见呀,你的搜索姿势不对而已
    icybee
        15
    icybee  
       2016 年 5 月 8 日
    个人习惯吧, python 优化完都一样
    loveuqian
        16
    loveuqian  
       2016 年 5 月 8 日
    @liuhaotian
    可是 i++是异步的啊
    elarity
        17
    elarity  
       2016 年 5 月 8 日
    编译器喜欢,就这么简单。
    fy
        18
    fy  
       2016 年 5 月 8 日   2
    首先是看看字节码,好像区别不大

    >>> import dis
    >>> dis.dis('a += 1')
    1 0 LOAD_NAME 0 (a)
    3 LOAD_CONST 0 (1)
    6 INPLACE_ADD
    7 STORE_NAME 0 (a)
    10 LOAD_CONST 1 (None)
    13 RETURN_VALUE
    >>>
    >>> dis.dis('a = a + 1')
    1 0 LOAD_NAME 0 (a)
    3 LOAD_CONST 0 (1)
    6 BINARY_ADD
    7 STORE_NAME 0 (a)
    10 LOAD_CONST 1 (None)
    13 RETURN_VALUE
    >>>

    然后去看字节码解析,貌似一毛一样

    ceval.c

    TARGET(BINARY_ADD) {
    PyObject *right = POP();
    PyObject *left = TOP();
    PyObject *sum;
    if (PyUnicode_CheckExact(left &&
    PyUnicode_CheckExact(right)) {
    sum = unicode_concatenate(left, right, f, next_instr);
    /* unicode_concatenate consumed the ref to v */
    }
    else {
    sum = PyNumber_Add(left, right);
    Py_DECREF(left);
    }
    Py_DECREF(right);
    SET_TOP(sum);
    if (sum == NULL)
    goto error;
    DISPATCH();
    }

    TARGET(INPLACE_ADD) {
    PyObject *right = POP();
    PyObject *left = TOP();
    PyObject *sum;
    if (PyUnicode_CheckExact(left) && PyUnicode_CheckExact(right)) {
    sum = unicode_concatenate(left, right, f, next_instr);
    /* unicode_concatenate consumed the ref to v */
    }
    else {
    sum = PyNumber_InPlaceAdd(left, right);
    Py_DECREF(left);
    }
    Py_DECREF(right);
    SET_TOP(sum);
    if (sum == NULL)
    goto error;
    DISPATCH();
    }

    然后观察实现:

    abstract.c

    PyObject *
    PyNumber_Add(PyObject *v, PyObject *w)
    {
    PyObject *result = binary_op1(v, w, NB_SLOT(nb_add));
    if (result == Py_NotImplemented) {
    PySequenceMethods *m = v->ob_type->tp_as_sequence;
    Py_DECREF(result);
    if (m && m->sq_concat) {
    return (*m->sq_concat)(v, w);
    }
    result = binop_type_error(v, w, "+");
    }
    return result;
    }


    PyObject *
    PyNumber_InPlaceAdd(PyObject *v, PyObject *w)
    {
    PyObject *result = binary_iop1(v, w, NB_SLOT(nb_inplace_add),
    NB_SLOT(nb_add));
    if (result == Py_NotImplemented) {
    PySequenceMethods *m = v->ob_type->tp_as_sequence;
    Py_DECREF(result);
    if (m != NULL) {
    binaryfunc f = NULL;
    f = m->sq_inplace_concat;
    if (f == NULL)
    f = m->sq_concat;
    if (f != NULL)
    return (*f)(v, w);
    }
    result = binop_type_error(v, w, "+=");
    }
    return result;
    }

    于是我思考之后得出了结论:
    他们有什么不同呢?最终调用的槽不同。

    但是 python 代码来测试的结果,确实是 += 比 = + 快一点
    fy
        19
    fy  
       2016 年 5 月 8 日
    另外 Python 的 int 和 str 一样是不可变对象,根本不会有 inc x 这样的东西
    tvallday
        20
    tvallday  
       2016 年 5 月 8 日
    参考
    https://en.wikipedia.org/wiki/Augmented_assignment

    因为编译器并不一定知道 i 是一个普通变量,也有可能是数组里面的元素或者其他复杂类型,这样第一种写法需要找两次 i 。
    est
        21
    est  
       2016 年 5 月 8 日
    += 是个原子操作。 但是 py 估计然并卵。
    qqmishi
        22
    qqmishi  
       2016 年 5 月 8 日 via Android   1
    +和=是同一个键打起来快,,,
    xuboying
        23
    xuboying  
       2016 年 5 月 8 日 via Android   1
    语言搞这种细节就没意思了
    soland
        24
    soland  
       2016 年 5 月 8 日
    编译有可能不一样。
    RitzoneX
        25
    RitzoneX  
       2016 年 5 月 8 日
    试下 i++
    latyas
        27
    latyas  
       2016 年 5 月 8 日
    所以标题应该问:这两个写法有什么区别 会更好一些
    MntCw
        28
    MntCw  
       2016 年 5 月 8 日 via Android
    存储器读一次和读两次的区别
    abscon
        29
    abscon  
       2016 年 5 月 8 日 via iPhone
    Python 不是鼓吹只有一种方法做事情么,禁止掉一个吧
    Finalcheat
        30
    Finalcheat  
       2016 年 5 月 8 日
    习惯问题吧,没有任何好处。
    jacy
        31
    jacy  
       2016 年 5 月 8 日
    后者有 B 格
    digimoon
        32
    digimoon  
       2016 年 5 月 8 日
    后者我一眼看过去没反应过来是什么东西,可能似乎大概有 B 格
    mhoudg
        33
    mhoudg  
       2016 年 5 月 8 日   2
    这个步骤的真实意图通常并非做一个加法运算,而是进行自增
    i += 1 的写法非常符合 “ i 自增 1 ”这个语言顺序,给人感觉很直观;
    而 i = i + 1 的写法会让人第一感受是一个赋值,第二感受是一个假发,相对 += 来说不那么直观

    我知道肯定有人会说第二种写法也很直观,而且我不打算讨论什么叫“直观”这个问题
    Patiencec
        34
    Patiencec  
       2016 年 5 月 8 日 via iPhone
    哈哈,打字习惯
    chrishine
        35
    chrishine  
       2016 年 5 月 8 日
    语法糖层面,如果 i 这个变量名很长,优势就出来了。比如你要给某个结构体的某个字段增加某个值。
    性能方面,我觉得编译器应该可以优化掉这种 case.
    zhuangzhuang1988
        36
    zhuangzhuang1988  
       2016 年 5 月 8 日
    @chrishine 标准 python 解释器 是不会优化的
    Joway
        37
    Joway  
       2016 年 5 月 8 日
    以前忘了听谁说的说前者是一个操作,后者是两个,还有那个 ++i 和 i++ 前缀加比后缀加要快。。。然而我觉得这玩意在编译器阶段就已经被优化了,没什么区别。。
    Exin
        38
    Exin  
       2016 年 5 月 8 日
    可以给自己续一秒
    abcdabcd987
        39
    abcdabcd987  
       2016 年 5 月 8 日
    刚写完一个编译器,看到这个问题简直泪流满面。比如下面这个句子:
    a[i][j][k] = a[i][j][k] + 1

    a[i][j][k] += 1
    两句话翻译出来指令数差了好多啊 T_T
    glennq
        40
    glennq  
       2016 年 5 月 9 日
    前者等价于 i = i.__add__(1),后者等价于 i.__iadd__(1),对于 int 这种不可变对象是没太大区别,但在可变对象的情况下不仅效率可能有较大差别,实际产生的效果也不一样。
    atpking
        41
    atpking  
       2016 年 5 月 9 日
    编译器会帮你优化这些的 现在的编译器已经不是石器时代了
    Ginson
        42
    Ginson  
       2016 年 5 月 9 日
    作为一个 0 基础新手,我还是觉得 i = i + 1 更直观些
    i + = 好在哪里?无所谓了,反正结果一样。
    iiduce
        43
    iiduce  
       2016 年 5 月 9 日
    当你找到自认为对的理由后,会有一种优越感。
    iverson68214
        44
    iverson68214  
       2016 年 5 月 9 日
    量名,差就出了
    error_count = error_count + 1

    error_count += 1
    firemiles
        45
    firemiles  
       2016 年 5 月 9 日
    python 用多了连这种举手之劳就可以写成 i += 1 的优化也不愿意做了吗,什么都指望编译器能优化不太好吧。
    knightdf
        46
    knightdf  
       2016 年 5 月 9 日
    @iverson68214 确实,第一种丑
    sweelia
        47
    sweelia  
       2016 年 5 月 9 日
    i = i++ [再见]
    winoros
        48
    winoros  
       2016 年 5 月 9 日
    @Joway ++i 是传引用直接改, i++要先拿个变量存下当前的值,然后增,最后把变量返回
    Joway
        49
    Joway  
       2016 年 5 月 9 日 via Android
    @winoros 我知道你说的,但是实际上我觉得编译器已经能够优化这点了,毕竟那么多人循环都写 i++ (逃
    Override
        50
    Override  
       2016 年 8 月 28 日
    更加"dry"

    你写成 i = i + 1 的话,你要修改 i 这个变量,变成 n = n + 1 ,需要修改两个地方,
    而写成 i += 1 ,你只需要修改一个地方就可以变成 n += 1
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2319 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 30ms UTC 01:37 PVG 09:37 LAX 17:37 JFK 20:37
    Do have faith in what you're doing.
    ubao msn 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