概要
Pythonで複数の文字列を連結する方法として、次の3つの方法の処理速度を比較します。
1 配列に格納して「.join()」で連結
l = []
l.append("a")
l.append("b")
l.append("c")
t = "".join(l)
print(t)
# abc
2 「StringIO」でwrite()を使う
from io import StringIO
b = StringIO()
b.write("a")
b.write("b")
b.write("c")
t = b.getvalue()
print(t)
# abc
3 文字列変数を「+」で連結
t = ""
t += "a"
t += "b"
t += "c"
print(t)
# abc
背景
大量の文字列を扱う際など、配列とjoin()を使うことが多かったのですが、サンプルコードなどではStringIOを使用しているものも見かけるため、調べてみました。
参考事例
2012年と古い記事ですが比較をしている記事がありました。
Lists vs. StringIO vs. Regular String Concat for building strings in Python
結果部分を引用します。
連結速度は
「+」<「.join()」<「StringIO」
となっています。
(注意:2025年では結果が違います)
IPython 0.10.1 -- An enhanced Interactive Python.
? -> Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python's own help system.
object? -> Details about 'object'. ?object also works, ?? prints more.
In [2]: from string_building_perf import *
In [3]: %timeit build_ul_list(100000)
10 loops, best of 3: 77.9 ms per loop
In [4]: %timeit build_ul_stringio(100000)
10 loops, best of 3: 109 ms per loop
In [5]: %timeit build_ul_concat(100000)
10 loops, best of 3: 66.1 ms per loop
In [6]: %timeit build_ul_list(100000, get_random_word)
1 loops, best of 3: 245 ms per loop
In [7]: %timeit build_ul_stringio(100000, get_random_word)
1 loops, best of 3: 269 ms per loop
In [8]: %timeit build_ul_concat(100000, get_random_word)
1 loops, best of 3: 203 ms per loop
比較(2025)
同じ方法で改めて計測してみます(Python3.12.3, ipython9.2.0)。
コードの一部をPython3に合わせて修正して使わせてもらっています。
# パターン1
%timeit build_ul_list(100000)
6.34 ms ± 95.4 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit build_ul_stringio(100000)
5.76 ms ± 86.4 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit build_ul_concat(100000)
6.25 ms ± 109 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
# パターン2
%timeit build_ul_list(100000, get_random_word)
19.6 ms ± 195 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit build_ul_stringio(100000, get_random_word)
18.7 ms ± 197 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit build_ul_concat(100000, get_random_word)
18.6 ms ± 130 μs per loop (mean ± std. dev. of 7 runs, 100 loops each)
「.join()」が若干遅いくらいで他は差が少ない結果です。
パターン1では「stringIO」が少し早いです。
結果
2025年現在では、どの連結方法を使っても速度面での差は少ないと言えそうです。
利用コード
2025年の比較では次のコードを使用しています。
オリジナルはリンクを参照してください。
from io import StringIO
from itertools import permutations
import string
import random
word = 'x' * 8
words = [''.join(p) for p in permutations(string.ascii_letters [:8])]
def get_8x():
return word
def get_random_word():
return random.choice(words)
def build_ul_list(linect, get_word=get_8x):
buffer = ['<ul>\n']
for i in range(linect):
buffer.append('<li>%s</li>\n' % get_word())
buffer.append('</ul>')
return ''.join(buffer)
def build_ul_stringio(linect, get_word=get_8x):
buffer = StringIO()
buffer.write('<ul>\n')
for i in range(linect):
buffer.write('<li>%s</li>\n' % get_word())
buffer.write('</ul>')
return buffer.getvalue()
def build_ul_concat(linect, get_word=get_8x):
buffer = '<ul>\n'
for i in range(linect):
buffer += ('<li>%s</li>\n' % get_word())
buffer += '</ul>'
return buffer