文字列結合のパフォーマンス

2.5.2でテスト。

import time

def profile(func):
  def foo(*a, **k):
    t = time.time()
    r = func(*a, **k)
    print '%s: %g sec elapsed' % (func.__name__, time.time() - t)
    return r
  return foo

@profile
def method1():
  out_str = ''
  for num in xrange(loop_count):
    out_str += `num`
  return out_str

@profile
def method2():
  from UserString import MutableString
  out_str = MutableString()
  for num in xrange(loop_count):
    out_str += `num`
  return out_str

@profile
def method3():
  from array import array
  char_array = array('c') 
  for num in xrange(loop_count):
    char_array.fromstring(`num`)
  return char_array.tostring()

@profile
def method4():
  str_list = []
  for num in xrange(loop_count):
    str_list.append(`num`)
  return ''.join(str_list)

@profile
def method5():
  from cStringIO import StringIO
  file_str = StringIO()
  for num in xrange(loop_count):
    file_str.write(`num`)
  return file_str.getvalue()

@profile
def method6():
  return ''.join([`num` for num in xrange(loop_count)])

@profile
def method7():
  return ''.join(`num` for num in xrange(loop_count))

@profile
def method8():
  return '%s'*loop_count % tuple(xrange(1, loop_count+1))
  
loop_count = 1000000
method1()
#method2()
method3()
method4()
method5()
method6()
method7()
method8()

実行結果。

method1: 5.283 sec elapsed
method3: 5.486 sec elapsed
method4: 0.547 sec elapsed
method5: 0.625 sec elapsed
method6: 0.438 sec elapsed
method7: 0.437 sec elapsed
method8: 0.454 sec elapsed

method2は時間かかりすぎで時間切れとみなした。「リスト内包表記(ジェネレータ内包表記) + join」が一番速い。短い文字列だと文字列を+演算子で結合する方が早いと思うが、長い文字列の場合はjoinを使用すべきだと思われる。リスト内包表記とジェネレータ内包表記は速度が変わらなかったのは意外だった。文字列フォーマットも意外と速いが、joinには一歩及ばず。


上記の参考サイトでは MutableString が速いとなっていたが、恐らくPythonのバージョンによるものではないだろうか?基本的にパフォーマンスはPythonのバージョンごとに計測しなおすべきだと思う。


3.0で文字列を表示するなら、print(*range(1, loop_count+1), sep='')という処理が速そうな気がする。Python 3.0では文字列フォーマットがかなり強化されたが、どうせだったらRubyやGroovyのような文字列に埋め込む形のやり方にしてほしかった。3.0のformatメソッドはC#っぽい気がするが、なんか中途半端。Pythonの文法ではRubyやGroovyのやり方は表現できないのだろうか?


結論は以下のとおり。


文字列結合は状況に応じて以下の3通りから最適なものを選択すれば良い。但し指針としては、+演算子は文字列が長い場合には遅いので注意が必要。

  • +演算子
  • join
  • フォーマット文字列