Python字符串格式化太慢了

时间:2010-04-14 13:03:42

标签: python string formatting

我使用以下代码记录地图,当它只包含零时它很快,但只要地图中有实际数据就会变得难以忍受地慢......有没有办法更快地做到这一点? / p>

log_file = open('testfile', 'w')
for i, x in ((i, start + i * interval) for i in range(length)):
    log_file.write('%-5d %8.3f %13g %13g %13g %13g %13g %13g\n' % (i, x,
        map[0][i], map[1][i], map[2][i], map[3][i], map[4][i], map[5][i]))

3 个答案:

答案 0 :(得分:3)

我建议您使用cProfile模块运行代码,并按照http://docs.python.org/library/profile.html中的说明对结果进行后处理。这将让您确切地知道在调用str.__mod__时花费了多少时间来进行字符串格式化以及花费多少时间来处理其他事情,比如编写文件并对{{1}执行__getitem__查找等等。

答案 1 :(得分:2)

首先我检查%反对反引用。 % 是比较快的。然后我检查%(元组)对'string'.format()。最初的错误让我觉得它更快。但不是。 %更快。

因此,您已经在Python中以最快的方式完成了大量的浮点到字符串转换。

下面的演示代码是丑陋的演示代码。请不要讲授xrange与范围或其他迂腐的问题。 KThxBye。

我的临时和高度不科学的测试表明,对于Linux上的Python 2.5上的(a)%(1.234)操作比Linux上的%2.6(1 .34,...)操作更快,对于下面的测试代码,条件是使用'string'.format()的尝试不适用于2.6之前的python版本。等等。

# this code should never be used in production.
# should work on linux and windows now.

import random
import timeit
import os
import tempfile


start = 0
interval = 0.1

amap = [] # list of lists
tmap = [] # list of tuples

def r():
    return random.random()*500

for i in xrange(0,10000):
        amap.append ( [r(),r(),r(),r(),r(),r()] )

for i in xrange(0,10000):
        tmap.append ( (r(),r(),r(),r(),r(),r()) )




def testme_percent():
    log_file = tempfile.TemporaryFile()
    try:
        for qmap in amap:
            s = '%g %g %g %g %g %g \n' % (qmap[0], qmap[1], qmap[2], qmap[3], qmap[4], qmap[5]) 
            log_file.write( s)
    finally:
        log_file.close();

def testme_tuple_percent():
    log_file = tempfile.TemporaryFile()
    try:    
        for qtup in tmap:
            s = '%g %g %g %g %g %g \n' % qtup
            log_file.write( s );
    finally:
        log_file.close();

def testme_backquotes_rule_yeah_baby():
    log_file = tempfile.TemporaryFile()
    try:
        for qmap in amap:
            s = `qmap`+'\n'
            log_file.write( s );
    finally:
        log_file.close();        

def testme_the_new_way_to_format():
    log_file = tempfile.TemporaryFile()
    try:
        for qmap in amap:
            s = '{0} {1} {2} {3} {4} {5} \n'.format(qmap[0], qmap[1], qmap[2], qmap[3], qmap[4], qmap[5]) 
            log_file.write( s );
    finally:
        log_file.close();

# python 2.5 helper
default_number = 50 
def _xtimeit(stmt="pass",  timer=timeit.default_timer,
           number=default_number):
    """quick and dirty"""
    if stmt<>"pass":
        stmtcall = stmt+"()"
        ssetup = "from __main__ import "+stmt
    else:
        stmtcall = stmt
        ssetup = "pass"
    t = timeit.Timer(stmtcall,setup=ssetup)
    try:
      return t.timeit(number)
    except:
      t.print_exc()


# no formatting operation in testme2

print "now timing variations on a theme"

#times = []
#for i in range(0,10):

n0 = _xtimeit( "pass",number=50)
print "pass = ",n0

n1 = _xtimeit( "testme_percent",number=50);
print "old style % formatting=",n1

n2 = _xtimeit( "testme_tuple_percent",number=50);
print "old style % formatting with tuples=",n2

n3 = _xtimeit( "testme_backquotes_rule_yeah_baby",number=50);
print "backquotes=",n3

n4 = _xtimeit( "testme_the_new_way_to_format",number=50);
print "new str.format conversion=",n4


#        times.append( n);




print "done"    

我认为你可以通过在其他地方构建你的浮动TUPLES来优化你的代码,无论你在哪里构建那个地图,首先构建你的元组列表,然后以这种方式应用fmt_string%元组:

for tup in mytups:
    log_file.write( fmt_str % tup )

通过将for-tuple部分从for循环中删除,我能够将8.7秒缩短到8.5秒。哪个不多。那个大男孩有浮点格式,我相信这总是很贵。

替代方案:

您是否考虑过不写文本这么大的日志,而是使用最快的“持久性”方法保存它们,然后在需要时编写一个简短的实用程序将它们转储到文本中?有些人将NumPy与非常大的数值数据集一起使用,似乎他们不会使用逐行转储来存储他们的东西。参见:

http://thsant.blogspot.com/2007/11/saving-numpy-arrays-which-is-fastest.html

答案 2 :(得分:0)

如果不想涉及优化 - 这段代码的泥潭,我会编写更像这样的代码:

log_file = open('testfile', 'w')
x = start
map_iter = zip(range(length), map[0], map[1], map[2], map[3], map[4], map[5])
fmt = '%-5d %8.3f %13g %13g %13g %13g %13g %13g\n'
for i, m0, m1, m2, m3, m4, m5 in mapiter:
    s = fmt % (i, x, m0, m1, m2, m3, m4, m5)
    log_file.write(s)
    x += interval

但我会推荐你​​在python builtins之后没有命名变量的建议,比如map