Python-String-Klasse wie StringBuilder in C #?


Antworten:


102

Es gibt keine Eins-zu-Eins-Korrelation. Einen wirklich guten Artikel finden Sie unter Effiziente String-Verkettung in Python :

Das Erstellen langer Zeichenfolgen in der Python-Programmiersprache kann manchmal zu sehr langsam laufendem Code führen. In diesem Artikel untersuche ich die Rechenleistung verschiedener String-Verkettungsmethoden.


27
Beachten Sie, dass dieser Artikel auf Python 2.2 basiert. Die Tests würden in einer modernen Version von Python wahrscheinlich etwas anders ablaufen (CPython optimiert normalerweise erfolgreich die Verkettung, aber Sie möchten sich in wichtigen Codes nicht darauf verlassen), und ein Generatorausdruck, bei dem er ein Listenverständnis verwendet, wäre erwägenswert .
Mike Graham

4
Es wäre gut, einige Highlights in diesem Artikel zu erwähnen, zumindest einige der Implementierungen (um Probleme mit der Verbindungsfäule zu vermeiden).
jpmc26

3
Methode 1: resultString + = appendString ist der schnellste nach Tests von @ Antoine-tran unten
Justas

5
Ihr Zitat beantwortet die Frage überhaupt nicht. Bitte fügen Sie die entsprechenden Teile in Ihre Antwort selbst ein, um den neuen Richtlinien zu entsprechen.
Fund Monica Klage

27

Ich habe den Code von Oliver Crow (Link von Andrew Hare) verwendet und ihn ein wenig angepasst, um Python 2.7.3 anzupassen. (mit timeit package). Ich lief auf meinem PC, Lenovo T61, 6 GB RAM, Debian GNU / Linux 6.0.6 (Squeeze).

Hier ist das Ergebnis für 10.000 Iterationen:

Methode 1: 0,0538418292999 Sekunden
Prozessgröße 4800 kb
Methode 2: 0,22602891922 Sekunden
Prozessgröße 4960 kb
Methode 3: 0,0605459213257 Sekunden
Prozessgröße 4980 kb
Methode 4: 0,0544030666351 Sekunden
Prozessgröße 5536 kb
Methode 5: 0,0551080703735 Sekunden
Prozessgröße 5272 kb
Methode 6: 0,0542731285095 Sekunden
Prozessgröße 5512 kb

und für 5.000.000 Iterationen (Methode 2 wurde ignoriert, weil sie wie für immer zu langsam lief):

Methode 1: 5,88603997231 Sekunden
Prozessgröße 37976 kb
Methode 3: 8,40748500824 Sekunden
Prozessgröße 38024 kb
Methode 4: 7,96380496025 Sekunden
Prozessgröße 321968 kb
method5: 8.03666186333 sec
Prozessgröße 71720 kb
Methode 6: 6,68192911148 Sekunden
Prozessgröße 38240 kb

Es ist ziemlich offensichtlich, dass Python-Leute großartige Arbeit geleistet haben, um die Verkettung von Strings zu optimieren, und wie Hoare sagte: "Vorzeitige Optimierung ist die Wurzel allen Übels" :-)


2
Anscheinend akzeptiert Hoare das nicht: hans.gerwitz.com/2004/08/12/…
Pimin Konstantin Kefaloukos

5
Es ist keine vorzeitige Optimierung, um fragile, interpretatorabhängige Optimierungen zu vermeiden. Wenn Sie jemals auf PyPy portieren möchten oder das Risiko eingehen, einen der vielen subtilen Fehlerfälle für die Optimierung zu treffen , gehen Sie richtig vor.
Veedrac

1
Es sieht so aus, als ob Methode 1 für den Compiler einfacher zu optimieren ist.
mbomb007

23

Sich auf Compiler-Optimierungen zu verlassen, ist fragil. Den in der akzeptierten Antwort und den von Antoine-tran angegebenen Zahlen verknüpften Benchmarks ist nicht zu trauen. Andrew Hare macht den Fehler, einen Aufruf an reprin seine Methoden aufzunehmen. Das verlangsamt alle Methoden gleichermaßen, verdeckt aber die wirkliche Strafe beim Erstellen des Strings.

Verwenden Sie join. Es ist sehr schnell und robuster.

$ ipython3
Python 3.5.1 (default, Mar  2 2016, 03:38:02) 
IPython 4.1.2 -- An enhanced Interactive Python.

In [1]: values = [str(num) for num in range(int(1e3))]

In [2]: %%timeit
   ...: ''.join(values)
   ...: 
100000 loops, best of 3: 7.37 µs per loop

In [3]: %%timeit
   ...: result = ''
   ...: for value in values:
   ...:     result += value
   ...: 
10000 loops, best of 3: 82.8 µs per loop

In [4]: import io

In [5]: %%timeit
   ...: writer = io.StringIO()
   ...: for value in values:
   ...:     writer.write(value)
   ...: writer.getvalue()
   ...: 
10000 loops, best of 3: 81.8 µs per loop

Ja, der reprAufruf dominiert die Laufzeit, aber es besteht keine Notwendigkeit, den Fehler persönlich zu machen.
Alex Reinking

3
@ AlexReinking sorry, nichts persönliches gemeint. Ich bin mir nicht sicher, warum du es für persönlich gehalten hast. Aber wenn es die Verwendung ihrer Namen war, habe ich diese nur verwendet, um auf die Antworten des Benutzers zu verweisen (stimmt mit Benutzernamen überein, nicht sicher, ob es einen besseren Weg gibt).
GrantJ

1
gutes Timing-Beispiel, das
Dateninitialisierungs-

19

Python hat mehrere Dinge, die ähnliche Zwecke erfüllen:

  • Eine übliche Methode, um große Zeichenfolgen aus Teilen zu erstellen, besteht darin, eine Liste von Zeichenfolgen zu erstellen und diese zu verbinden, wenn Sie fertig sind. Dies ist eine häufig verwendete Python-Sprache.
    • Um Zeichenfolgen zu erstellen, die Daten mit Formatierung enthalten, müssen Sie die Formatierung separat durchführen.
  • Zum Einfügen und Löschen auf Zeichenebene würden Sie eine Liste mit Zeichenfolgen der Länge 1 führen. (Um dies aus einer Zeichenfolge zu machen, würden Sie aufrufen list(your_string). Sie können auch eine UserString.MutableStringdafür verwenden.
  • (c)StringIO.StringIO ist nützlich für Dinge, die sonst eine Datei benötigen würden, aber weniger für die allgemeine Zeichenfolgenerstellung.

10

Mit Methode 5 von oben (The Pseudo File) können wir eine sehr gute Leistung und Flexibilität erzielen

from cStringIO import StringIO

class StringBuilder:
     _file_str = None

     def __init__(self):
         self._file_str = StringIO()

     def Append(self, str):
         self._file_str.write(str)

     def __str__(self):
         return self._file_str.getvalue()

jetzt benutze es

sb = StringBuilder()

sb.Append("Hello\n")
sb.Append("World")

print sb


-1

Es gibt kein explizites Analogon - ich denke, es wird erwartet, dass Sie Zeichenfolgenverkettungen (wahrscheinlich wie oben beschrieben optimiert) oder Klassen von Drittanbietern (ich bezweifle, dass sie viel effizienter sind) verwenden - Listen in Python sind dynamisch typisiert, sodass sie nicht schnell funktionieren char [] für Puffer, wie ich annehme). Stringbuilder-ähnliche Klassen sind keine vorzeitige Optimierung, da Strings in vielen Sprachen angeboren sind (Unveränderlichkeit) - dies ermöglicht viele Optimierungen (z. B. Verweisen auf denselben Puffer für Slices / Teilzeichenfolgen). Stringbuilder- / Stringbuffer- / Stringstream-ähnliche Klassen arbeiten viel schneller als das Verketten von Strings (wodurch viele kleine temporäre Objekte erzeugt werden, für die noch Zuordnungen und Speicherbereinigung erforderlich sind) und sogar das Formatieren von printf-ähnlichen Tools für das Formatieren von Zeichenfolgen, ohne dass der Aufwand für das Formatieren von Formatierungsmustern ziemlich aufwendig ist viele Formataufrufe.


-4

Wenn Sie hier nach einer schnellen String-Verkettungsmethode in Python suchen, benötigen Sie keine spezielle StringBuilder-Klasse. Einfache Verkettung funktioniert genauso gut ohne den Leistungsverlust in C #.

resultString = ""

resultString += "Append 1"
resultString += "Append 2"

Siehe Antoine-trans Antwort für Leistungsergebnisse

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.