Wofür wird StringIO in Python in der Realität verwendet?

75

Ich bin kein Profi und habe mir den Kopf zerkratzt, um zu verstehen, wofür genau StringIO verwendet wird. Ich habe mich im Internet nach Beispielen umgesehen. Fast alle Beispiele sind jedoch sehr abstrakt. Und sie zeigen nur, wie man es benutzt. Aber keiner von ihnen zeigt "warum" und "unter welchen Umständen" sollte / wird man es benutzen? Danke im Voraus

ps nicht zu verwechseln mit dieser Frage zum Stackoverflow: StringIO Verwendung, die String und StringIo vergleicht.

Hossein
quelle

Antworten:

89

Es wird verwendet, wenn Sie eine API haben, die nur Dateien akzeptiert, aber eine Zeichenfolge verwenden müssen. So komprimieren Sie beispielsweise eine Zeichenfolge mit dem Modul gzip in Python 2:

import gzip
import StringIO

stringio = StringIO.StringIO()
gzip_file = gzip.GzipFile(fileobj=stringio, mode='w')
gzip_file.write('Hello World')
gzip_file.close()

stringio.getvalue()
Petr Viktorin
quelle
2
mit anderen Worten duck typing
Abdelouahab
2
Seit Python 3.2 verfügt das gzip-Modul über Funktionen, mit denen Daten direkt komprimiert werden. (Aber jede bekannte Open-Source-Bibliothek, die derzeit StringIO benötigt, wird solche Funktionen wahrscheinlich nach einiger Zeit erweitern. Anstatt nach einem neuen Beispiel zu suchen, lasse ich gzip hier.)
Petr Viktorin
36

Mit StringIO haben Sie dateiähnlichen Zugriff auf Zeichenfolgen, sodass Sie ein vorhandenes Modul verwenden können, das sich mit einer Datei befasst, fast nichts ändert und sie mit Zeichenfolgen arbeiten lässt.

Angenommen, Sie haben einen Logger, der Dinge in eine Datei schreibt, und möchten stattdessen die Protokollausgabe über das Netzwerk senden. Sie können die Datei lesen und ihren Inhalt in das Netzwerk schreiben, oder Sie können das Protokoll in ein StringIO-Objekt schreiben und an sein Netzwerkziel senden, ohne das Dateisystem zu berühren. StringIO macht es einfach, den ersten Weg zu gehen und dann zum zweiten Weg zu wechseln.

nmichaels
quelle
stringIO ist auch hilfreich beim Schreiben einer Datei direkt in S3 (dh ohne dass zuerst lokal gespeichert und dann hochgeladen werden muss).
7bStan
17

In Fällen, in denen Sie ein dateiähnliches Objekt möchten, das wie eine Datei ACTS-fähig ist, aber in einen speicherinternen Zeichenfolgenpuffer schreibt: StringIO ist das Tool. Wenn Sie große Zeichenfolgen erstellen, z. B. Nur-Text-Dokumente, und viele Zeichenfolgen verketten, ist es möglicherweise einfacher, nur StringIO anstelle einer Reihe mystr += 'more stuff\n'von Operationen zu verwenden.

Nathanismus
quelle
3
Ich habe auch festgestellt StringIO, dass es erheblich schneller ist, wenn Sie mit mehreren Megabyte Zeichendaten im Vergleich zu Ausdrücken wie mystr += "more stuff\n"innerhalb einer Schleife arbeiten, insbesondere wenn Sie cStringIO.StringIOstatt nur verwenden können io.StringIO.
Selten 'Wo ist Monica' bedürftig
@SeldomNeedy Hast du es bewertet? Es mag 2016 wahr gewesen sein, aber die Verkettung von Zeichenfolgen mit + = ist heutzutage ziemlich optimiert (es verwendet den Referenzzähler, um die Zeichenfolge an Ort und Stelle zu mutieren, wenn dies sicher möglich ist). Benchmark: $ python3 -m timeit -s "from io import StringIO; line = 'a'*80" $'s = StringIO()\nfor i in range(10000): s.write(line)\ns = s.getvalue()'500 loops, best of 5: 599 usec per loop; python3 -m timeit -s "line = 'a'*80" $'s = ""\nfor i in range(10000): s += line'500 loops, best of 5: 588 usec per loop
Clément
@ Clément Ich bezog mich auf Python 2.x; cStringIOexistiert nicht einmal in Python 3. Es ist gut zu sehen, dass die naive Implementierung in 3.x gut optimiert ist!
Selten 'Wo ist Monica' bedürftig
@SeldomNeedy +=wurde auch in Python 2 gut optimiert, AFAICT: Die +=Version des obigen Benchmarks ist zehnmal so schnell wie StringIO und dreimal so schnell wie StringIO in Python2. (Auch in Ihrem Beitrag wird erwähnt io.StringIO; ist das nicht nur Python 3?)
Clément
@ Clément docs.python.org/2/library/stringio.html
Selten 'Wo ist Monica' bedürftig
10

Einige Dinge, für die ich es persönlich verwendet habe:

  1. Caching ganzer Dateien. Ich habe ein Skript, das PDFs liest und verschiedene Dinge überprüft. Die von mir verwendete PDF-Bibliothek nimmt eine geöffnete Datei in ihren Dokumentkonstruktor. Ich habe ursprünglich nur das PDF geöffnet, das ich lesen wollte. Als ich es jedoch so änderte, dass die gesamte Datei auf einmal in den Speicher gelesen und dann ein StringIO-Objekt an die PDF-Bibliothek übergeben wurde, wurde die Laufzeit meines Skripts halbiert.

  2. Aufgeschobenes Drucken. Das gleiche Skript druckt vor jedem gelesenen PDF einen Header. Ich kann jedoch in der Befehlszeile angeben, ob bestimmte Tests in der Konfigurationsdatei ignoriert oder nur bestimmte eingeschlossen werden sollen. Wenn ich alle Tests für eine bestimmte PDF-Datei ignoriere, möchte ich nicht, dass der Header gedruckt wird, aber ich weiß nicht, wie viele Tests ich ausgeführt habe, bis ich die Tests ausgeführt habe (die Tests können auch dynamisch definiert werden). Also erfasse ich den Header in einem StringIO-Objekt, indem sys.stdoutich ihn verweise und jedes Mal, wenn ich einen Test durchführe, überprüfe ich, ob dieses Objekt etwas enthält. Wenn ja, drucke ich es dann aus und setze es auf leer zurück. Voila, nur PDFs mit Tests haben Header gedruckt.

irgendwie
quelle
9

Ich habe StringIO gerade in der Praxis für zwei Dinge verwendet:

  • Testen eines Skripts, das viel printArbeit leistet , durch Umleiten sys.stdoutzu einer StringIOInstanz zur einfachen Analyse;
  • Erstellen eines garantierten wohlgeformten XML-Dokuments (eine benutzerdefinierte API-Anforderung) mit ElementTreeund anschließend writezum Senden über eine HTTP-Verbindung.

Nicht, dass du es StringIO oft brauchst , aber manchmal ist es ziemlich nützlich.

9000
quelle
4

Ich habe es anstelle von Textdateien für Unit-Tests verwendet.

Zum Beispiel, um eine CSV-Datei zum Testen mit Pandas (Python 3) zu erstellen:

import io
f = io.StringIO("id,name\n1,brian\n2,amanda\n3,zoey\n")
df = pd.read_csv(f) # pandas takes a file path or a file-like object

Aus der Dokumentation hier :

Ein speicherinterner Stream für Text-E / A. Der Textpuffer wird verworfen, wenn die Methode close () aufgerufen wird.

Der Anfangswert des Puffers kann durch Angabe von initial_value festgelegt werden.

Methode getvalue (): Gibt einen Str zurück, der den gesamten Inhalt des Puffers enthält.

Brian Burns
quelle
1

Django hat eine Funktion, mit call_commandder Verwaltungsbefehle aufgerufen werden. Diese Funktion druckt die Ausgabe an stdout und gibt keinen Wert zurück. Wenn Sie wissen möchten, ob der Befehl erfolgreich ausgeführt wurde oder nicht, müssen Sie die Ausgabe prüfen und entscheiden.

Mit StringIO können Sie die Ausgabe erfassen und prüfen, ob die gewünschte Ausgabe gewünscht wird oder nicht.

with io.StringIO() as output:
    call_command('custom_command', stdout=output)
    if 'Success' not in output.getvalue():
        print('Custom command failed...')
ChillarAnand
quelle