Wie füge ich in Python eine Zeichenfolge an eine andere an?

Ich möchte eine effiziente Möglichkeit, eine Zeichenfolge an eine andere in Python anzuhängen.

var1 = "foo" var2 = "bar" var3 = var1 + var2 

Gibt es eine gute integrierte Methode zu verwenden?

Solutions Collecting From Web of "Wie füge ich in Python eine Zeichenfolge an eine andere an?"

Wenn Sie nur einen Verweis auf eine Zeichenfolge haben und Sie eine andere Zeichenfolge an das Ende verketten, behandelt CPython dies jetzt speziell und versucht, die Zeichenfolge an Ort und Stelle zu erweitern.

Das Endergebnis ist, dass die Operation amortisiert ist O (n).

z.B

 s = "" for i in range(n): s+=str(i) 

war früher O (n ^ 2), aber jetzt ist es O (n).

Von der Quelle (bytesobject.c):

 void PyBytes_ConcatAndDel(register PyObject **pv, register PyObject *w) { PyBytes_Concat(pv, w); Py_XDECREF(w); } /* The following function breaks the notion that strings are immutable: it changes the size of a string. We get away with this only if there is only one module referencing the object. You can also think of it as creating a new string object and destroying the old one, only more efficiently. In any case, don't use this if the string may already be known to some other part of the code... Note that if there's not enough memory to resize the string, the original string object at *pv is deallocated, *pv is set to NULL, an "out of memory" exception is set, and -1 is returned. Else (on success) 0 is returned, and the value in *pv may or may not be the same as on input. As always, an extra byte is allocated for a trailing \0 byte (newsize does *not* include that), and a trailing \0 byte is stored. */ int _PyBytes_Resize(PyObject **pv, Py_ssize_t newsize) { register PyObject *v; register PyBytesObject *sv; v = *pv; if (!PyBytes_Check(v) || Py_REFCNT(v) != 1 || newsize < 0) { *pv = 0; Py_DECREF(v); PyErr_BadInternalCall(); return -1; } /* XXX UNREF/NEWREF interface should be more symmetrical */ _Py_DEC_REFTOTAL; _Py_ForgetReference(v); *pv = (PyObject *) PyObject_REALLOC((char *)v, PyBytesObject_SIZE + newsize); if (*pv == NULL) { PyObject_Del(v); PyErr_NoMemory(); return -1; } _Py_NewReference(*pv); sv = (PyBytesObject *) *pv; Py_SIZE(sv) = newsize; sv->ob_sval[newsize] = '\0'; sv->ob_shash = -1; /* invalidate cached hash value */ return 0; } 

Es ist leicht genug, empirisch zu verifizieren.

 $ python -m timeit -s "s = ''" "für i in xrange (10): s + = 'a'"
 1000000 Schleifen, das Beste aus 3: 1,85 usec pro Schleife
 $ python -m timeit -s "s = ''" "für i in xrange (100): s + = 'a'"
 10000 Loops, Bestes von 3: 16,8 Usec pro Loop
 $ python -m timeit -s "s = ''" "für i in xrange (1000): s + = 'a'"
 10000 Loops, Bestes von 3: 158 Usec pro Loop
 $ python -m timeit -s "s = ''" "für i in xrange (10000): s + = 'a'"
 1000 Loops, Best of 3: 1,71 ms pro Schleife
 $ python -m timeit -s "s = ''" "für i in xrange (100000): s + = 'a'"
 10 Schleifen, das Beste aus 3: 14,6 ms pro Schleife
 $ python -m timeit -s "s = ''" "für i in xrange (1000000): s + = 'a'"
 10 Schleifen, das Beste aus 3: 173 ms pro Schleife

Es ist jedoch wichtig zu beachten, dass diese Optimierung nicht Teil der Python-Spezifikation ist. Es ist nur in der cPython-Implementierung, soweit ich weiß. Die gleichen empirischen Tests auf Pypy oder Jython zum Beispiel könnten die ältere O (n ** 2) -performance zeigen.

 $ pypy -m timeit -s "s = ''" "für i in xrange (10): s + = 'a'"
 10000 Loops, Bestes von 3: 90,8 Usec pro Loop
 $ pypy -m timeit -s "s = ''" "für i in xrange (100): s + = 'a'"
 1000 Loops, Bestes von 3: 896 Usec pro Loop
 $ pypy -m timeit -s "s = ''" "für i in xrange (1000): s + = 'a'"
 100 Loops, Bestes von 3: 9,03 ms pro Loop
 $ pypy -m timeit -s "s = ''" "für i in xrange (10000): s + = 'a'"
 10 Loops, Best of 3: 89,5 ms pro Loop

So weit so gut, aber dann,

 $ pypy -m timeit -s "s = ''" "für i in xrange (100000): s + = 'a'"
 10 Loops, Best of 3: 12,8 Sek. Pro Loop

autsch noch schlechter als quadratisch. So macht Pypy etwas, das gut mit kurzen Strings arbeitet, aber für größere Strings schlecht funktioniert.

Nicht vorzeitig optimieren. Wenn Sie keinen Grund zu der Annahme haben, dass ein Geschwindigkeitsengpass durch Stringverkettungen verursacht wird, bleiben Sie einfach bei + und += :

 s = 'foo' s += 'bar' s += 'baz' 

Das heißt, wenn Sie nach etwas wie dem StringBuilder von Java streben, besteht das kanonische Python-Idiom darin, Elemente zu einer Liste hinzuzufügen und dann am Ende str.join zu verwenden, um sie alle zu verketten:

 l = [] l.append('foo') l.append('bar') l.append('baz') s = ''.join(l) 

Nicht.

Das heißt, in den meisten Fällen ist es besser, die gesamte Zeichenfolge auf einmal zu generieren, anstatt sie an eine vorhandene Zeichenfolge anzuhängen.

Zum Beispiel nicht tun: obj1.name + ":" + str(obj1.count)

Stattdessen: benutze "%s:%d" % (obj1.name, obj1.count)

Das wird einfacher zu lesen und effizienter sein.

 str1 = "Hello" str2 = "World" newstr = " ".join((str1, str2)) 

Das verbindet str1 und str2 mit einem Leerzeichen als Trennzeichen. Sie können auch "".join(str1, str2, ...) . str.join() nimmt ein iterables, also str.join() Sie die Strings in eine Liste oder ein Tupel setzen.

Das ist ungefähr so ​​effizient wie es für eine integrierte Methode möglich ist.

Es hängt wirklich von Ihrer Anwendung ab. Wenn Sie Hunderte von Wörtern durchlaufen und sie alle in einer Liste anhängen möchten, ist .join() besser. Aber wenn Sie einen langen Satz zusammenstellen, sollten Sie besser += .

Wenn Sie viele Append-Vorgänge ausführen müssen, um eine große Zeichenfolge zu erstellen, können Sie StringIO oder cStringIO verwenden. Die Schnittstelle ist wie eine Datei. zB: Sie write , um Text an ihn anzuhängen.

Wenn Sie nur zwei Zeichenfolgen anhängen, verwenden Sie einfach + .

 a='foo' b='baaz' a.__add__(b) out: 'foobaaz' 

Grundsätzlich kein Unterschied. Der einzige konsistente Trend ist, dass Python mit jeder Version langsamer zu werden scheint … 🙁


Liste

 %%timeit x = [] for i in range(100000000): # xrange on Python 2.7 x.append('a') x = ''.join(x) 

Python 2.7

1 Schleife, Best of 3: 7,34 s pro Schleife

Python 3.4

1 Schleife, Best of 3: 7,99 s pro Schleife

Python 3.5

1 Schleife, Best of 3: 8,48 s pro Schleife

Python 3.6

1 Schleife, beste von 3: 9,93 s pro Schleife


Zeichenfolge

 %%timeit x = '' for i in range(100000000): # xrange on Python 2.7 x += 'a' 

Python 2.7 :

1 Schleife, Best of 3: 7,41 s pro Schleife

Python 3.4

1 Schleife, beste 3: 9,08 s pro Schleife

Python 3.5

1 Schleife, Best of 3: 8,82 s pro Schleife

Python 3.6

1 Schleife, beste von 3: 9,24 s pro Schleife

Hängen Sie Strings mit der function __add__ an

 str = "Hello" str2 = " World" st = str.__add__(str2) print(st) 

Ausgabe

 Hello World