【发布时间】:2019-04-04 22:06:14
【问题描述】:
我必须将许多短字符串连接到一个字典条目中,我意识到这很慢(大致是二次的)。但是,如果预先将字符串连接起来,然后添加到字典中,那么连接时间几乎是线性的。
这是一个简单的插图。此函数基本上连接许多字符串并创建一个包含连接字符串的单个条目的字典。第一个函数直接在条目“d[key] += str(num)”上执行,第二个函数在字符串“out_str += str(num)”上执行。下面打印了时间,可以看到二次和线性行为。
我想知道开销是从哪里来的。谢谢!
def method1(loop_count):
""" String concatenation on dictionary entry directly (slow)"""
out_str = ''
d={}
key = 'key'
d[key] = ''
for num in range(loop_count):
d[key] += str(num)
return d
def method2(loop_count):
""" Concatenation 'on string' and then add to dictionary (fast) """
out_str = ''
d={}
key = 'key'
for num in range(loop_count):
out_str += str(num)
d[key] = out_str
return d
def method3(loop_count):
""" Concatenation 'on string' and then add to dictionary (fast) """
out_str = ''
d={}
key = 'key'
out_str = ''.join(str(n) for n in range(loop_count))
d[key] = out_str
return d
from timeit import default_timer as timer
import numpy as np
for p in range(10,20):
t0 = timer()
method1(np.power(2,p))
t1 = timer()
method2(np.power(2,p))
t2 = timer()
method3(np.power(2,p))
t3 = timer()
print("2^{}:\t{:4.2g}\t{:4.2g}\t{:4.2g}".format(p, t1-t0, t2-t1, t3-t2))
in dict += join
2^10: 0.0003 0.0002 0.0002
2^11: 0.00069 0.0004 0.00038
2^12: 0.0017 0.00079 0.00076
2^13: 0.0057 0.0016 0.0015
2^14: 0.021 0.0032 0.0031
2^15: 0.095 0.0065 0.0065
2^16: 0.77 0.013 0.013
2^17: 3.2 0.026 0.027
2^18: 15 0.052 0.052
2^19: 67 0.1 0.11
注意:这不是一个严格意义上关于有效字符串连接的问题。它是关于何时在字符串连接中进行字符串优化。
注意 2:我使用“join”习语添加了第三种方法,它与 += 所用的时间完全相同
正如答案所暗示的,这似乎是一个优化问题。进一步的测试似乎证明了这一点。下面的代码显示 += 重用了许多字符串,无论字典条目中的连接是否:
a=''
for n in range(10):
print(id(a))
a+=str(n)
140126222965424
140126043294720
140126043294720
140126043294720
140126043294720
140126043294720
140126043294720
140126043294720
140126042796464
140126042796464
d={}
d['key']=''
for n in range(10):
print(id(d['key']))
d['key']+=str(n)
140126222965424
140126042643120
140126042643232
140126042643176
140126042643120
140126042643232
140126042643176
140126042643120
140126042761520
140126042761456
我仍然想知道为什么会这样。谢谢!
【问题讨论】:
-
Python 优化了一些字符串连接。我的猜测是“一些”在字典项目中不包括
+=。顺便说一句,您可能会发现将它们累积在一个列表中然后从那里加入它们会更快(您必须尝试一下)。 -
是的,因为您应该假设与
+=的字符串连接是二次的。当您使用带有字符串的+=进行循环时,已经做出了一些努力来添加不会在后台使用二次时间算法的优化,但是解释器很难优化除了最明显的实例之外的任何内容。在您的情况下,解释器无法对其进行优化。但是你不应该依赖解释器优化,而是使用 canonical 方式来连接许多字符串:使用''.join -
已更新加入。 += 的相同表现。
-
所以看来问题是没有进入字典的优化。我怀疑类似的事情。谢谢!我想知道是否有任何描述此问题的 python 文档...
标签: python python-3.x