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

2020-07-30 13:04:21 +08:00
 Alpacino

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

4692 次点击
所在节点    问与答
42 条回复
yangyaofei
2020-07-30 14:58:11 +08:00
都用 Python 了,还在乎那点性能损失么...
真的在乎性能就不会用 python 吧,或者多线程多进程比这个性能提升多多了.
JCZ2MkKb5S8ZX9pq
2020-07-30 14:58:19 +08:00
python cook book 好像有提过这个
但以我平时写的那些小破代码来说,可读性和直观程度更加重要一些。优不优化区别不大,真搞到需要优化了,我应该也能有预算找人帮我整个重构了。
goodryb
2020-07-30 15:12:04 +08:00
所以比较牛逼的写法应该是什么样子的,都用 python 了不是更应该注重开发效率吗
changwei
2020-07-30 15:54:24 +08:00
我很好奇编译器能不能自动识别出这种大量+=的语句,然后底层自动转换成 stringBuffer 来拼接?就像 c 或者 java 的 for 循环里面可以把 i++优化成++i 一样,我觉得这种比较有规律并且很普遍的写法在编译器上可以考虑一下特殊优化了。
a132811
2020-07-30 17:06:35 +08:00
几乎没有差别, 时间都是随着 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
2020-07-30 17:09:35 +08:00
纠结这个能省几秒啊,不应该是写得差不多了再来查哪里是性能瓶颈然后针对优化么
wittyfans
2020-07-30 17:19:19 +08:00
在 stack overflow 上也看到了这个问题,可以看看。

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

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

https://gist.github.com/llllllllll/7ad5905275233f1fb3868f4a67793616
Alpacino
2020-07-31 02:30:51 +08:00
所以如果要避免的话,就用''.join() ?
Acoolda
2020-07-31 10:03:35 +08:00
别听那些沙雕文章忽悠,实用易懂是关键。
julyclyde
2020-07-31 16:42:01 +08:00
如果效率有问题那是语言自己没做好自己的工作

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/694317

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX