-
-
Save levic/fbcac9ea3974d2cbdfb187c7e655f2e5 to your computer and use it in GitHub Desktop.
Lists vs. StringIO vs. Regular String Concat for building strings in Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
================================= | |
Python 3.11 | |
================================= | |
Concatenating 5 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.629 | |
build_ul_concat : 1.013 | |
Concatenating 32 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.356 | |
build_ul_concat : 1.074 | |
Concatenating 302 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.253 | |
build_ul_concat : 1.375 | |
Concatenating 3,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.296 | |
build_ul_concat : 1.398 | |
Concatenating 30,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.23 | |
build_ul_concat : 1.567 | |
Concatenating 300,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.296 | |
build_ul_concat : 1.615 | |
Concatenating 3,000,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.22 | |
build_ul_concat : 1.6 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Results are pretty noisy as each test only runs for ~1.5sec; use as a rough guide only | |
================================= | |
Python 3.6 | |
================================= | |
Concatenating 5 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.702 | |
build_ul_concat : 1.045 | |
Concatenating 32 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.342 | |
build_ul_concat : 1.021 | |
Concatenating 302 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.215 | |
build_ul_concat : 1.257 | |
Concatenating 3,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.237 | |
build_ul_concat : 1.48 | |
Concatenating 30,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.255 | |
build_ul_concat : 1.672 | |
Concatenating 300,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.015 | |
build_ul_concat : 1.141 | |
Concatenating 3,000,002 strings... | |
build_ul_list : 1.0 | |
build_ul_stringio : 1.333 | |
build_ul_concat : 1.811 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
from io import StringIO | |
from itertools import permutations | |
import string | |
import random | |
import sys | |
import timeit | |
word = 'x' * 8 | |
words = [''.join(p) for p in permutations(string.ascii_letters[:8])] | |
def get_8x(): | |
return word | |
next_word = -1 | |
def get_random_word(): | |
global next_word | |
next_word += 1 | |
next_word %= len(words) | |
return words[next_word] | |
#return random.choice(words) | |
def build_ul_list(linect, get_word=get_8x): | |
buffer = ['<ul>\n'] | |
for i in range(linect): | |
buffer.extend([ | |
'<li>', get_word(), '</li>', | |
]) | |
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>') | |
buffer.write(get_word()) | |
buffer.write('</li>') | |
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>' | |
buffer += get_word() | |
buffer += '</li>' | |
buffer += '</ul>' | |
def run_tests(size, iter_count): | |
string_count = 2 + 3 * size | |
print(f"Concatenating {string_count:,} strings", end="", flush=True) | |
fastest = None | |
results = {} | |
for fn in (build_ul_list, build_ul_stringio, build_ul_concat): | |
elapsed = timeit.timeit(lambda: fn(size, get_word=get_random_word), number=iter_count) | |
if fastest is None or fastest > elapsed: | |
fastest = elapsed | |
results[fn] = elapsed | |
print(".", end="", flush=True) | |
print() | |
for fn, elapsed in results.items(): | |
print(f"{fn.__name__:20}: {elapsed/fastest:.4}") | |
if __name__ == "__main__": | |
print("=================================") | |
print(f"Python {'.'.join(str(x) for x in sys.version_info[:2])}") | |
print("=================================") | |
run_tests(1, 5000000) | |
run_tests(10, 500000) | |
run_tests(100, 50000) | |
run_tests(1000, 5000) | |
run_tests(10000, 500) | |
run_tests(100000, 50) | |
run_tests(1000000, 5) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment