Aangezien Python's string
niet veranderd kan worden, vroeg ik me af hoe je een string efficiënter aan elkaar kunt plakken?
Ik kan zo schrijven:
s += stringfromelsewhere
of zoals dit:
s = []
s.append(somestring)
later
s = ''.join(s)
Terwijl ik deze vraag schreef, vond ik een goed artikel over dit onderwerp.
http://www.skymind.com/~ocrow/python_string/
Maar het'is in Python 2.x., dus de vraag zou zijn is er iets veranderd in Python 3?
Als je veel waarden aaneenrijgt, dan geen van beide. Een lijst appen is duur. Daar kun je StringIO voor gebruiken. Vooral als je het opbouwt over een heleboel bewerkingen.
from cStringIO import StringIO
# python3: from io import StringIO
buf = StringIO()
buf.write('foo')
buf.write('foo')
buf.write('foo')
buf.getvalue()
# 'foofoofoo'
Als je al een complete lijst terug hebt van een andere bewerking, dan gebruik je gewoon de ''.join(aList)
Uit de python FAQ: Wat is de meest efficiënte manier om veel strings aan elkaar te koppelen?
str en bytes objecten zijn onveranderlijk, daarom is het aaneenschakelen van veel strings aan elkaar is inefficiënt omdat elke aaneenschakeling een nieuw object maakt. In het algemene geval zijn de totale runtime-kosten kwadratisch in de totale lengte van de string.
Om veel str-objecten te verzamelen, is het aanbevolen idiomatisch om ze in een lijst te plaatsen en str.join() aan het eind aan te roepen:
chunks = [] for s in my_strings: chunks.append(s) resultaat = ''.join(chunks)
(een ander redelijk efficiënt idioom is het gebruik van io.StringIO)
Om veel byte-objecten te verzamelen, is het aanbevolen idioom om een bytearray-object uit te breiden met in-place concatenation (de += operator):
resultaat = bytearray() voor b in mijn_bytes_objects: resultaat += b
Edit: Ik was dom en had de resultaten achterstevoren geplakt, waardoor het leek alsof appen naar een lijst sneller was dan cStringIO. Ik heb ook tests toegevoegd voor bytearray/str concat, evenals een tweede ronde van tests met een grotere lijst met grotere strings. (python 2.7.3)
ipython test voorbeeld voor grote lijsten met strings
try:
from cStringIO import StringIO
except:
from io import StringIO
source = ['foo']*1000
%%timeit buf = StringIO()
for i in source:
buf.write(i)
final = buf.getvalue()
# 1000 loops, best of 3: 1.27 ms per loop
%%timeit out = []
for i in source:
out.append(i)
final = ''.join(out)
# 1000 loops, best of 3: 9.89 ms per loop
%%timeit out = bytearray()
for i in source:
out += i
# 10000 loops, best of 3: 98.5 µs per loop
%%timeit out = ""
for i in source:
out += i
# 10000 loops, best of 3: 161 µs per loop
## Repeat the tests with a larger list, containing
## strings that are bigger than the small string caching
## done by the Python
source = ['foo']*1000
# cStringIO
# 10 loops, best of 3: 19.2 ms per loop
# list append and join
# 100 loops, best of 3: 144 ms per loop
# bytearray() +=
# 100 loops, best of 3: 3.8 ms per loop
# str() +=
# 100 loops, best of 3: 5.11 ms per loop
Hoewel enigszins gedateerd, Code Like a Pythonista: Idiomatic Python beveelt join()
aan boven +
in deze sectie. Net als PythonSpeedPerformanceTips in zijn sectie over string concatenation, met de volgende disclaimer:
De nauwkeurigheid van deze sectie wordt betwist met betrekking tot latere versies van Python. In CPython 2.5, is string concatenation redelijk snel, hoewel dit misschien niet geldt voor andere Python implementaties. Zie ConcatenationTestCode voor een discussie.