在 Python 中打印字符串的最有效方法是啥?

Posted

技术标签:

【中文标题】在 Python 中打印字符串的最有效方法是啥?【英文标题】:Most efficient way to print strings in Python?在 Python 中打印字符串的最有效方法是什么? 【发布时间】:2010-11-08 21:47:05 【问题描述】:

所以根据http://wiki.python.org/moin/PythonSpeed/PerformanceTips 的优化提示,应该使用

来连接字符串

out = "<html>%(head)s%(prologue)s%(query)s%(tail)s</html>" % locals() 而不是out = "<html>" + head + prologue + query + tail + "</html>" 我的问题是,如果我想打印而不是存储值,这是否相同?另外,将连续的打印语句全部放在一行上会更快吗?会不会更好用

print "Some word"
print "Another line"
print "something else"

print '''Some word
Another line
something else'''

提前致谢!

【问题讨论】:

默认情况下 print 会在字符串末尾添加换行符,因此您的第一个示例不等同于第二个。 谢谢,安德鲁,我错过了,我会修复它 请参阅 Joel Spolsky 的 Back to Basics,了解有关此问题的讨论。虽然这篇文章是关于 C 的,但它讨论的问题也适用于 Python(和许多其他语言)。 如果你不需要支持比python2.6更早的版本,最好使用str.format来做插值。例如。 print "My name is name".format(name='Parker') 我希望控制台输出所需的时间会使字符串构造方式的差异相形见绌。打印后,一切都很慢。 【参考方案1】:

对于只有一个字符串引用的(相当常见的)情况,字符串连接得到了改进。请参阅stringobject.c中的 PyString_ConcatAndDel

所以通常循环中的连接是线性的,因为字符串只有一个引用

这是一个演示该行为的简单实验。当没有空间扩展字符串时,id() 会发生变化

>>> s = ""
>>> prev_id = None
>>> for i in range(1000):
...  s += "*"
...  if prev_id != id(s):
...   print id(s), len(s)
...   prev_id = id(s)
... 
3077352864 1
3077437728 2
3077434328 9
3077428384 17
3077379928 25
3077291808 33
3077712448 41
3077358800 49
3077394728 57
3077667680 65
3077515120 73
3077354176 81
3077576488 89
3077559200 97
3077414248 105
3077670336 113
3077612160 121
3077707040 129
3077526040 137
3077571472 145
3077694944 153
3077595936 161
3077661904 169
3077552608 177
3077715680 185
3077583776 193
3077244304 201
3077604560 209
3077510392 217
3077334304 225
144468768 233
144787416 245
144890104 389

【讨论】:

很酷的东西,我必须坚持 katrielalex 的回答,但你会得到 +1 来为我解释这个!我想你之前也已经回答了我的问题,所以一如既往,谢谢! 我发现 python 用于此优化的加速速率以及我们最终得到不同输出的事实很有趣。我已经习惯了通过一个常数因子(通常是 2)来增加容量的相当无聊的算法,但显然 python 做了一些不同的事情。无论哪种方式,这都会使追加线性操作。【参考方案2】:

您的问题实际上并不是关于打印字符串的最有效方式,而是关于格式化它们以进行输出,无论如何您都应该使用format,因为它不仅仅是简单的连接。不过,这里有一些关于串联的注意事项。


编辑:重写以包含一些细节

打印无关紧要。重要的一点是,由于某些语言处理字符串连接的方式,连接大量字符串可能是二次顺序的。 (非常幼稚和基本的)推理是,要连接两个字符串,您必须遍历第一个字符串的所有字符,然后附加第二个字符串的所有字符。因此,如果要连接十个字符串,首先遍历第一个并附加第二个,然后遍历第一个+第二个并附加第三个,然后遍历第一个+第二个+第三个并附加第四个,依此类推。

因此,连接的幼稚实现将导致您做的工作比您需要的多得多。事实上,在 Python 的早期版本中,这是一个问题。但是,@gnibbler 在 cmets 中指出,现在以后的版本通常会对此进行优化,因此完全没有争议。

连接字符串的 Python 习惯用法是 "".join(...)。这完全绕过了任何可能的问题,并且无论如何都是标准的成语。如果您希望能够通过附加来构造字符串,请查看StringIO

>>> from io import StringIO
>>> foo = StringIO()
>>> for letter in map(chr, range(128)):
...     foo.write(letter)
...
>>> foo.seek(0)
0
>>> foo.read()
'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f\x10\x11\x12\x13\x14\
x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !"#$%&\'()*+,-./0123456789:;<=>?@ABC
DEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz|~\x7f'

【讨论】:

顺便说一句,这个连接问题并不特定于 Python,它适用于许多语言。此外,这是一个非常受欢迎的面试问题。 好的,谢谢!所以为了澄清一下,打印语句的数量并不重要,但是当我打印时,我不应该使用'+'? 请注意,在 Python 2.5 及更高版本中,“用 + 连接大量字符串实际上是二次顺序。”不再是正确的(但我仍然避免它以支持其他成语)。 @jimbob,连接并不总是二次的 - 请参阅 ***.com/questions/4128494 值得注意的是,串联的实际操作比任何少量字符串的替代方法都要快得多。此外,join 几乎完全不在此处,因为问题询问了 format 方法更快而 join 无用的插值。【参考方案3】:

对于打印,无需连接:

print "<html>", head, prologue, query, tail, "</html>"

这同样有效(末尾的逗号阻止\n):

print "<html>",
print head,
...
print "</html>"

我认为答案是否定的,不要仅仅为了打印而连接,这会使事情变慢。但是你真的不应该相信我的话,只需用timeit写一些测试和配置文件。

【讨论】:

这在 Python3 中也可以使用 print 功能,您可以指定自己的分隔符。例如。 print("foo", "bar", sep="-")

以上是关于在 Python 中打印字符串的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

创建初始重复数据的二维字符串数组的最有效方法是啥?

在 Python 中查找数字的所有因数的最有效方法是啥?

Python - 生成填充的最有效方法是啥?

使用 PHP 在一个字符串中搜索多个标记的最有效方法是啥?

在 PostgreSQL 中提取拆分字符串的最后一部分的最有效方法是啥?

在 Django 模型中存储列表的最有效方法是啥?