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
terence4444
V2EX  ›  Python

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

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

    个人猜测, 不对请轻喷
    chunqiuyiyu
        6
    chunqiuyiyu  
       2016-05-08 14:46:33 +08:00
    少打一个字 提升效率 节约生命
    kalintw
        7
    kalintw  
       2016-05-08 14:47:28 +08:00
    可以显示出 PyCharm 的存在感。哈哈。
    crab
        8
    crab  
       2016-05-08 14:51:43 +08:00
    一样吧。和大括号另外一行
    jsonline
        10
    jsonline  
       2016-05-08 14:55:00 +08:00
    你为什么要发帖
    junnplus
        11
    junnplus  
       2016-05-08 14:59:36 +08:00   ❤️ 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-05-08 15:07:10 +08:00
    @junnplus 这是 stackoverflow 的站内搜索?搜索引擎对符号搜索视而不见……
    liuhaotian
        13
    liuhaotian  
       2016-05-08 15:09:34 +08:00 via iPhone
    只有 i++才有效率的提高因为可以直接 INC X
    junnplus
        14
    junnplus  
       2016-05-08 15:16:18 +08:00
    @terence4444 并不会视而不见呀,你的搜索姿势不对而已
    icybee
        15
    icybee  
       2016-05-08 15:18:02 +08:00
    个人习惯吧, python 优化完都一样
    loveuqian
        16
    loveuqian  
       2016-05-08 15:19:33 +08:00
    @liuhaotian
    可是 i++是异步的啊
    elarity
        17
    elarity  
       2016-05-08 15:20:57 +08:00
    编译器喜欢,就这么简单。
    fy
        18
    fy  
       2016-05-08 15:27:18 +08:00   ❤️ 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-05-08 15:28:30 +08:00
    另外 Python 的 int 和 str 一样是不可变对象,根本不会有 inc x 这样的东西
    tvallday
        20
    tvallday  
       2016-05-08 15:28:31 +08:00
    参考
    https://en.wikipedia.org/wiki/Augmented_assignment

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

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

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

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

    你写成 i = i + 1 的话,你要修改 i 这个变量,变成 n = n + 1 ,需要修改两个地方,
    而写成 i += 1 ,你只需要修改一个地方就可以变成 n += 1
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1340 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 23:38 · PVG 07:38 · LAX 15:38 · JFK 18:38
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.