Alpacino
V2EX  ›  问与答

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

  •  1
     
  •   Alpacino · Jul 30, 2020 · 6390 views
    This topic created in 2287 days ago, the information mentioned may be changed or developed.

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

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

    我寻思着 string.join 也不怎么科班吧?可能我上课没听课(++手动滑稽)
    love
    love
    Jul 30, 2020❤️1
    16
    python 本身就效率很低,就不用追求这么细了吧
    Vegetable
    Vegetable
    Jul 30, 2020
    17
    https://gist.github.com/luliangce/f33d175e5a53db83ee2d2af91d3711be

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

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

    不科班的说法只能说明这人有点自以为是。
    lbp0200
    lbp0200
    Jul 30, 2020
    28
    想要性能,首先抛弃 Python,改用 C
    caviar
    caviar
    Jul 30, 2020
    29
    个人感觉说这话的人也不是特别的科班。
    确实 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
    caviar
    Jul 30, 2020
    30
    呃... wtf-python 我是很早之前读的,好像记错了,那一段并没有详细讲这件事....
    cyspy
    cyspy
    Jul 30, 2020 via Android
    31
    难道 for +=比 join 易懂吗?
    nutting
    nutting
    Jul 30, 2020
    32
    一条语句没什么吧,循环里才值得商榷
    acumen
    acumen
    Jul 30, 2020
    33
    任何抛开场景的讨论都是耍流氓(手动狗头
    classyk
    classyk
    Jul 30, 2020
    34
    @sagaxu 当然可以,注意 reserve 函数的使用。
    AlohaV2
    AlohaV2
    Jul 30, 2020
    35
    @sagaxu C++有 small string optimization,前面字串不太大的话应该还行
    AlohaV2
    AlohaV2
    Jul 30, 2020
    36
    科班不科班都可以这样写,这么写可读性挺好的。
    要不要这样写取决于你这行代码在整个程序里运行几遍(换句话说性能分析出来占多少的执行时间比例)。
    matrix1010
    matrix1010
    Jul 30, 2020
    37
    前几天 twitter 上刚看到有人讨论过

    https://gist.github.com/llllllllll/7ad5905275233f1fb3868f4a67793616
    Alpacino
    Alpacino
    OP
    Jul 31, 2020
    38
    所以如果要避免的话,就用''.join() ?
    Acoolda
    Acoolda
    Jul 31, 2020 via Android
    39
    别听那些沙雕文章忽悠,实用易懂是关键。
    julyclyde
    julyclyde
    Jul 31, 2020
    40
    如果效率有问题那是语言自己没做好自己的工作
    zxCoder
    zxCoder
    Jul 31, 2020
    41
    所以应该怎么写呢?上面这么多回复好像都没提到过
    Alpacino
    Alpacino
    OP
    Aug 1, 2020
    42
    @zxCoder 同问。。好像是用''.join()
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Privacy   ·   Solana   ·   1963 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 95ms · UTC 16:48 · PVG 00:48 · LAX 08:48 · JFK 11:48
    ♥ Do have faith in what you're doing.