The time difference you're seeing comes from creating the list to be passed to join
. And while you can get a small speedup from using a tuple instead, it's still going to be slower than just concatenating with +
when there are only a few short strings.
It would be different if you had an iterable of strings to start with, rather than an object with strings as attributes. Then you could call join
directly on the iterable, rather than needing to build a new one for each call.
Here's some testing I did with the timeit
module:
import timeit
short_strings = ["foo", "bar", "baz"]
long_strings = [s*1000 for s in short_strings]
def concat(a, b, c):
return a + b + c
def concat_from_list(lst):
return lst[0] + lst[1] + lst[2]
def join(a, b, c):
return "".join([a, b, c])
def join_tuple(a, b, c):
return "".join((a, b, c))
def join_from_list(lst):
return "".join(lst)
def test():
print("Short strings")
print("{:20}{}".format("concat:",
timeit.timeit(lambda: concat(*short_strings))))
print("{:20}{}".format("concat_from_list:",
timeit.timeit(lambda: concat_from_list(short_strings))))
print("{:20}{}".format("join:",
timeit.timeit(lambda: join(*short_strings))))
print("{:20}{}".format("join_tuple:",
timeit.timeit(lambda: join_tuple(*short_strings))))
print("{:20}{}\n".format("join_from_list:",
timeit.timeit(lambda: join_from_list(short_strings))))
print("Long Strings")
print("{:20}{}".format("concat:",
timeit.timeit(lambda: concat(*long_strings))))
print("{:20}{}".format("concat_from_list:",
timeit.timeit(lambda: concat_from_list(long_strings))))
print("{:20}{}".format("join:",
timeit.timeit(lambda: join(*long_strings))))
print("{:20}{}".format("join_tuple:",
timeit.timeit(lambda: join_tuple(*long_strings))))
print("{:20}{}".format("join_from_list:",
timeit.timeit(lambda: join_from_list(long_strings))))
Output:
Python 3.3.0 (v3.3.0:bd8afb90ebf2, Sep 29 2012, 10:57:17) [MSC v.1600 64 bit (AMD64)] on win32
Type "copyright", "credits" or "license()" for more information.
>>> ================================ RESTART ================================
>>>
>>> test()
Short strings
concat: 0.5453461176251436
concat_from_list: 0.5185697357936024
join: 0.7099379456477868
join_tuple: 0.5900842397209949
join_from_list: 0.4177281794285359
Long Strings
concat: 2.002303591571888
concat_from_list: 1.8898819841869416
join: 1.5672863477837913
join_tuple: 1.4343144915087596
join_from_list: 1.231374639083505
So, joining from an already existing list is always fastest. Concatenating with +
is faster for individual items if they are short, but for long strings it is always slowest. I suspect the difference shown between concat
and concat_from_list
comes from the unpacking of the lists in the function call in the test code.