I know that the pythonic way of concatenating a list of strings is to use
l =["a", "b", "c"]
"".join(l)
But how would I do this if I have a list of objects which contain a string (as an attribute), without reassigning the string?
I guess I could implement __str__(self)
. But that's a workaround that I would prefer not to use.
I guess the most pythonic way to do this would be using generator expression / list comprehension.
If the string for example is an attribute of the object obj_instance.str_attr
then just run:
"".join(x.str_attr for x in l)
or
"".join([x.str_attr for x in l])
edited: see discussion on the performance below (they claim that list comprehension - 2nd option is faster).
The performance difference between generator expression and list comprehension is easy to measure:
python --version && python -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join(obj.a for obj in l)"
Python 2.7.12
10 loops, best of 3: 87.2 msec per loop
python --version && python -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join([obj.a for obj in l])"
Python 2.7.12
10 loops, best of 3: 77.1 msec per loop
python3.4 --version && python3.4 -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join(obj.a for obj in l)"
Python 3.4.5
10 loops, best of 3: 77.4 msec per loop
python3.4 --version && python3.4 -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join([obj.a for obj in l])"
Python 3.4.5
10 loops, best of 3: 66 msec per loop
python3.5 --version && python3.5 -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join(obj.a for obj in l)"
Python 3.5.2
10 loops, best of 3: 82.8 msec per loop
python3.5 --version && python3.5 -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join([obj.a for obj in l])"
Python 3.5.2
10 loops, best of 3: 64.9 msec per loop
python3.6 --version && python3.6 -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join(obj.a for obj in l)"
Python 3.6.0
10 loops, best of 3: 84.6 msec per loop
python3.6 --version && python3.6 -m timeit -s \
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \
"''.join([obj.a for obj in l])"
Python 3.6.0
10 loops, best of 3: 64.7 msec per loop
It turns out that list comprehension is consistently faster than generator expression:
But note that memory consumption for list comprehension is 2x.
Dockerfile
you can run on your hardware to get your results, like docker build -t test-so . && docker run --rm test-so
.
FROM saaj/snake-tank
RUN echo '[tox] \n\
envlist = py27,py33,py34,py35,py36 \n\
skipsdist = True \n\
[testenv] \n\
commands = \n\
python --version \n\
python -m timeit -s \\\n\
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \\\n\
"str().join(obj.a for obj in l)" \n\
python -m timeit -s \\\n\
"import argparse; l = [argparse.Namespace(a=str(i)) for i in range(1000000)]" \\\n\
"str().join([obj.a for obj in l])"' > tox.ini
CMD tox
You can convert all your string attributes to list of strings:
string_list = [myobj.str for myobj in l]
The code above creates list of strings using generator. Afterwards u would use a standard way to concatenate strings:
"".join(string_list)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With