V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
V2EX 提问指南
GeekHub
Alpacino
V2EX  ›  问与答

Python 中 string += 'a' 这种写法效率很低吗?

  •  1
     
  •   Alpacino · 60 天前 · 2599 次点击
    这是一个创建于 60 天前的主题,其中的信息可能已经有所发展或是发生改变。

    在别的论坛上看见:“你 python for loop 还 string += “a”,这一下子就暴露不科班了。” 这个说法。

    42 条回复    2020-08-01 10:16:43 +08:00
    gwy15
        1
    gwy15   60 天前
    py str 不可变,如果要拼接字符串,类似 java 的 sb,用 List[str] 再 join 。
    sagaxu
        2
    sagaxu   60 天前 via Android
    随便什么语言这么写都慢
    Procumbens
        3
    Procumbens   60 天前
    @sagaxu C++不慢
    sagaxu
        4
    sagaxu   60 天前 via Android
    @Procumbens C++也慢,这种写法不能提前分配好长度合适的内存
    Hstar
        6
    Hstar   60 天前
    是 for loop 结合 string += 'a' 在 python 中慢
    假设目前 string 为 "aa"内存地址是 a1,在一次+=之后会生成一个新的字符串对象 "aaa" 存在 a2 并将 string 指向 a2
    所以 for loop 套 += 字符串操作会产生 N 个字符串对象的创建操作,效率较慢
    deorth
        7
    deorth   60 天前
    所以说怎样写才快
    binux
        8
    binux   60 天前 via Android
    @sagaxu #2 js 在 v8 下不慢
    STRRL
        9
    STRRL   60 天前 via Android   ❤️ 7
    反对这种写个 += 就暴露什么科班不科班。。
    过早优化乃万恶之源
    JeffGe
        10
    JeffGe   60 天前 via Android
    @realityone 我看这里面写的是 Python 2
    CallMeReznov
        11
    CallMeReznov   60 天前
    所以说怎样写才快?
    heygum97
        12
    heygum97   60 天前 via iPhone
    我寻思搜索引擎是不好用吗 这种问题
    djFFFFF
        13
    djFFFFF   60 天前
    这不一定是说效率低吧,python 语法糖比较多,for loop 三四行的代码很多时候 list comprehension 一行代码就搞定了
    binbinyouliiii
        14
    binbinyouliiii   60 天前 via Android
    正式项目不能这么写,自己为了 debug 随便你
    marcong95
        15
    marcong95   60 天前
    所以所谓的科班就要先 malloc 再 strcat 么(手动滑稽)

    我寻思着 string.join 也不怎么科班吧?可能我上课没听课(++手动滑稽)
    love
        16
    love   60 天前   ❤️ 1
    python 本身就效率很低,就不用追求这么细了吧
    Vegetable
        17
    Vegetable   60 天前


    这和循环的规模有很明显的关系。
    单个循环次数比较小时,直接拼接效果更好,循环次数达到一定量级之后使用列表才有意义,这个量级我测试大概在 1000 左右,而且持续提高规模并不会明显提高差距。
    楼上给的测试链接看起来,并不是很具有代表意义。
    Trim21
        18
    Trim21   60 天前
    正经项目拼接字符串都是用 StringIO 的吗
    iyaozhen
        19
    iyaozhen   60 天前
    2.6 好像就有优化过了,你可以试试,实际不慢(或者没那么夸张)
    该用还是用,一般循环次数也是有限,肯定不是性能问题的大头,甚至末尾都算不上
    misaka19000
        20
    misaka19000   60 天前
    反编译看一下字节码不就知道了
    yangyaofei
        21
    yangyaofei   60 天前
    都用 Python 了,还在乎那点性能损失么...
    真的在乎性能就不会用 python 吧,或者多线程多进程比这个性能提升多多了.
    JCZ2MkKb5S8ZX9pq
        22
    JCZ2MkKb5S8ZX9pq   60 天前
    python cook book 好像有提过这个
    但以我平时写的那些小破代码来说,可读性和直观程度更加重要一些。优不优化区别不大,真搞到需要优化了,我应该也能有预算找人帮我整个重构了。
    goodryb
        23
    goodryb   60 天前
    所以比较牛逼的写法应该是什么样子的,都用 python 了不是更应该注重开发效率吗
    changwei
        24
    changwei   60 天前
    我很好奇编译器能不能自动识别出这种大量+=的语句,然后底层自动转换成 stringBuffer 来拼接?就像 c 或者 java 的 for 循环里面可以把 i++优化成++i 一样,我觉得这种比较有规律并且很普遍的写法在编译器上可以考虑一下特殊优化了。
    a132811
        25
    a132811   60 天前
    几乎没有差别, 时间都是随着 n 线性增长

    ```python
    >>> timeit.timeit('for i in range(int(1e8)):s+="a"', setup='s=""', number=1)
    11.196388629000012

    >> timeit.timeit('for i in range(int(1e8)):s.write("s")', setup='from io import StringIO; s=StringIO()', number=1)
    8.931465667999987

    >>> timeit.timeit('"".join(["a" for i in range(int(1e8))])', setup='from io import StringIO; s=StringIO()', number=1)
    4.056428481000012
    ```
    MinQ
        26
    MinQ   60 天前   ❤️ 1
    纠结这个能省几秒啊,不应该是写得差不多了再来查哪里是性能瓶颈然后针对优化么
    wittyfans
        27
    wittyfans   60 天前 via iPhone
    在 stack overflow 上也看到了这个问题,可以看看。

    https://stackoverflow.com/questions/39675898/is-python-string-concatenation-bad-practice

    不科班的说法只能说明这人有点自以为是。
    lbp0200
        28
    lbp0200   60 天前
    想要性能,首先抛弃 Python,改用 C
    caviar
        29
    caviar   60 天前
    个人感觉说这话的人也不是特别的科班。
    确实 python 的 str 是 immutable 的,所以理论上 for loop 中 使用 string += "a" 的复杂度非常恐怖,尤其是在 string 很长的情况下,毕竟每次都要完整复制一份。
    但是实际上因为这个 case 太常见了,CPython 很早就有这个优化。即,如果这个 string 没有别的 reference ( non-alised )的时候,会直接 destructive update (官方的叫法是 in-place string concatenation )。因此从某种角度上说,python 的 str 可能会是 mutable 的,类似 list,每次创建时增长一下预留的空间。详细的说明可以看 wtf-python 里的 let's make a giant string
    https://github.com/satwikkansal/wtfpython#-lets-make-a-giant-string

    当然如果场景合适或数量非常大甚至是瓶颈的话,还是用 join 之类的为好。
    caviar
        30
    caviar   60 天前
    呃... wtf-python 我是很早之前读的,好像记错了,那一段并没有详细讲这件事....
    cyspy
        31
    cyspy   60 天前 via Android
    难道 for +=比 join 易懂吗?
    nutting
        32
    nutting   60 天前
    一条语句没什么吧,循环里才值得商榷
    acumen
        33
    acumen   60 天前
    任何抛开场景的讨论都是耍流氓(手动狗头
    classyk
        34
    classyk   60 天前
    @sagaxu 当然可以,注意 reserve 函数的使用。
    AlohaV2
        35
    AlohaV2   60 天前
    @sagaxu C++有 small string optimization,前面字串不太大的话应该还行
    AlohaV2
        36
    AlohaV2   60 天前
    科班不科班都可以这样写,这么写可读性挺好的。
    要不要这样写取决于你这行代码在整个程序里运行几遍(换句话说性能分析出来占多少的执行时间比例)。
    matrix1010
        37
    matrix1010   59 天前
    前几天 twitter 上刚看到有人讨论过

    Alpacino
        38
    Alpacino   59 天前
    所以如果要避免的话,就用''.join() ?
    Acoolda
        39
    Acoolda   59 天前 via Android
    别听那些沙雕文章忽悠,实用易懂是关键。
    julyclyde
        40
    julyclyde   59 天前
    如果效率有问题那是语言自己没做好自己的工作
    zxCoder
        41
    zxCoder   58 天前
    所以应该怎么写呢?上面这么多回复好像都没提到过
    Alpacino
        42
    Alpacino   58 天前
    @zxCoder 同问。。好像是用''.join()
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   感谢   ·   实用小工具   ·   2916 人在线   最高记录 5168   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 11:44 · PVG 19:44 · LAX 04:44 · JFK 07:44
    ♥ Do have faith in what you're doing.