繁体   English   中英

Python字符串串联循环

[英]Python string concatenation loop

%timeit为这两个实现提供的结果让我感到惊讶:

def f1():                                                                       
    s = ''                                                                    
    for i in range(len(values)):                                                
        s += str(values[i][0])                                                
        s += '\t'                                                             
        s += str(values[i][1])                                    
        s += '\r\n'                                                           
    return s  

def f2():                                                                       
    return ''.join((                                                            
                str(ts) + '\t' + str(v) + '\r\n'                                  
                for ts, v in values                                             
            ))  

知道values是大约2400个元组的列表。 f1()是我在一个由同事编写的脚本中找到的原始代码,该脚本更熟悉C / C ++,而在他写Python时对Python更为熟悉,而f2是恕我直言,我将为相同的处理编写的Pythonic风格越多。

我本来希望f2f1快得多,这主要是因为f1使用了许多串联和字符串重新分配,但是%timeit给出了两者的大小顺序相同(大约18ns),更令人惊讶的是,给f2 1ns更快,有时1ns。

这样的结果可能是什么解释?

[7月14日编辑]修复了f1,以用具有相同名称的局部变量覆盖str 但是,概要文件代码中不存在此错误。

由于以下原因,f2代码仍然受字符串连接的约束

str(ts) + '\\t' + str(v) + '\\r\\n'

它比基于字符串concat的原始版本要差的事实,可能是由于另一个问题中提到的实现细节。

如果将内部串联更改为也使用连接,则将获得更好的性能。

def f2(values):                                                                       
    return '\r\n'.join(
        ('\t'.join([str(ts), str(v)])
      for ts, v in values))

我可以肯定地说,您的测试方法无效,正如Py2.7的repl.itPy3的 repl.it所证明的那样 相同的代码,如下所示,但结果有所不同:

f1是您的f1函数
f2是您的f2函数
f3是使用c样式字符串格式"%s" % str f2函数
f4是使用.format() f2函数

结果:

Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.8.2] on linux

1.67547893524
1.33767485619
0.72606086731
1.32540607452

有一些区别,但是在任何情况下f1都不会超过以下任何一种方法。

Python 3.6.1 (default, Dec 2015, 13:05:11)
[GCC 4.8.2] on linux

3.0050943629757967
2.016791722999187
0.9476796620001551
1.9396837950043846

在这两种情况下,c样式字符串格式化的速度都快两倍以上。

使用的功能:

def f1():
    s = ''
    for i in range(len(values)):
        s += str(values[i][0])
        s += '\t'
        s += str(values[i][1])
        s += '\r\n'
    return s

def f2():    
    return ''.join((                        
        str(ts) + '\t' + str(v) + '\r\n'                
        for ts, v in values))

def f3():           
    return ''.join((
        "%s\t%s\r\n" % (ts, v)  
        for ts, v in values))

def f4():
    return ''.join((
        "{}\t{}\r\n".format(ts, v)
        for ts, v in values))

有趣的是,通过对f1函数进行少量更改,我们可以利用 danny引用的字节码加速来达到不错的速度:

def f1opt():
    s = ''
    for i in range(len(values)):
        s += str(values[i][0]) + '\t' + str(values[i][1]) + '\r\n'
    return s

产量

Python 2.7.10 (default, Jul 14 2015, 19:46:27)
[GCC 4.8.2] on linux

f1()         1.68486714363
f1bytecode() 0.999644994736

由于观察到的结果令我有些惊讶,因此我使用以下脚本进行了相同的分析:

import random
import timeit

data = [(random.randint(0, 100000), random.randint(0, 1000)) for _ in range(0, 2500)]

def f1():
    return ''.join(('{}\t{}\r\n'.format(ts, v) for ts, v in data))

def f2():
    s = ''
    for i in range(len(data)):
        s += str(data[i][0])
        s += '\t'
        s += str(data[i][1])
        s += '\r\n'

    return s


if __name__ == '__main__':
    repeat = 10000

    for f in ['f1', 'f2']:
        t = timeit.timeit(
            '%s()' % f, number=repeat, setup="from __main__ import %s" % f
        )
        print(
            "%s : avg time per loop = %f ms" % (f, t * 1000 / repeat)
        )

现在的输出是:

    f1 : avg time per loop = 0.779966 ms
    f2 : avg time per loop = 1.144340 ms

这更符合预期的结果。

我将进行更多调查,以了解两种测试在行为上的差异。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM