StringIO in Python3


474

Ich verwende Python 3.2.1 und kann das StringIOModul nicht importieren . Ich benutze io.StringIOund es funktioniert, aber ich kann es nicht mit benutzen numpyist genfromtxtwie folgt aus :

x="1 3\n 4.5 8"        
numpy.genfromtxt(io.StringIO(x))

Ich erhalte folgende Fehlermeldung:

TypeError: Can't convert 'bytes' object to str implicitly  

und wenn ich schreibe import StringIO, heißt es

ImportError: No module named 'StringIO'

Antworten:


774

Wenn ich Import StringIO schreibe, heißt es, dass es kein solches Modul gibt.

Von den Neuerungen in Python 3.0 :

Die StringIOund cStringIOModule sind weg. Importieren Sie stattdessen das io Modul und verwenden Sie io.StringIOoder io.BytesIOfür Text bzw. Daten.

.


Eine möglicherweise nützliche Methode zum Korrigieren von Python 2-Code, um auch in Python 3 (Vorbehalt-Emptor) zu funktionieren:

try:
    from StringIO import StringIO ## for Python 2
except ImportError:
    from io import StringIO ## for Python 3

Hinweis: Dieses Beispiel ist möglicherweise tangential zum Hauptproblem der Frage und wird nur berücksichtigt, wenn das fehlende StringIOModul generisch behandelt wird. Eine direktere Lösung der Nachricht TypeError: Can't convert 'bytes' object to str implicitlyfinden Sie in dieser Antwort .


13
Erwähnenswert ist, dass diese nicht gleich sind, sodass Sie am Ende TypeErrors (Zeichenfolgenargument erwartet, 'Bytes' erhalten) erhalten können, wenn Sie diese Änderung isoliert vornehmen. Sie müssen Btyes und Str (Unicode) in Python 3 sorgfältig unterscheiden.
Andy Hayden

7
Für Neulinge wie mich bedeutet StringIO von io import, dass Sie es als StringIO () und nicht als io.StringIO () aufrufen.
Noumenon

11
Wie man tatsächlich mit Python 2 und 3 kompatibel ist: nurfrom io import StringIO
Oleh Prypin

8
Dies ist einfach falsch für numpy.genfromtxt () in Python 3. Bitte beziehen Sie sich auf die Antwort von Roman Shapovalov.
Bill Huang

2
@nobar: Letzteres. Die ursprüngliche Frage verwendet Python 3.x, von dem das Modul entfernt StringIOist und from io import BytesIOstattdessen angewendet werden sollte. Habe mich auf Python 3.5 @ eclipse pyDev + win7 x64 getestet. Bitte lassen Sie mich wissen, wenn ich falsch lag, danke.
Bill Huang


70

Unter Python 3 wird numpy.genfromtxtein Byte-Stream erwartet. Verwenden Sie Folgendes:

numpy.genfromtxt(io.BytesIO(x.encode()))

24

Vielen Dank an OP für Ihre Frage und Roman für Ihre Antwort. Ich musste ein bisschen suchen, um das zu finden; Ich hoffe das Folgende hilft anderen.

Python 2.7

Siehe: https://docs.scipy.org/doc/numpy/user/basics.io.genfromtxt.html

import numpy as np
from StringIO import StringIO

data = "1, abc , 2\n 3, xxx, 4"

print type(data)
"""
<type 'str'>
"""

print '\n', np.genfromtxt(StringIO(data), delimiter=",", dtype="|S3", autostrip=True)
"""
[['1' 'abc' '2']
 ['3' 'xxx' '4']]
"""

print '\n', type(data)
"""
<type 'str'>
"""

print '\n', np.genfromtxt(StringIO(data), delimiter=",", autostrip=True)
"""
[[  1.  nan   2.]
 [  3.  nan   4.]]
"""

Python 3.5:

import numpy as np
from io import StringIO
import io

data = "1, abc , 2\n 3, xxx, 4"
#print(data)
"""
1, abc , 2
 3, xxx, 4
"""

#print(type(data))
"""
<class 'str'>
"""

#np.genfromtxt(StringIO(data), delimiter=",", autostrip=True)
# TypeError: Can't convert 'bytes' object to str implicitly

print('\n')
print(np.genfromtxt(io.BytesIO(data.encode()), delimiter=",", dtype="|S3", autostrip=True))
"""
[[b'1' b'abc' b'2']
 [b'3' b'xxx' b'4']]
"""

print('\n')
print(np.genfromtxt(io.BytesIO(data.encode()), delimiter=",", autostrip=True))
"""
[[  1.  nan   2.]
 [  3.  nan   4.]]
"""

Beiseite:

dtype = "| Sx", wobei x = eines von {1, 2, 3, ...}:

dtypes. Unterschied zwischen S1 und S2 in Python

"Die Zeichenfolgen | S1 und | S2 sind Datentypdeskriptoren. Das erste bedeutet, dass das Array Zeichenfolgen der Länge 1 enthält, das zweite Zeichen der Länge 2. ..."



17

Der Code von Roman Shapovalov sollte sowohl in Python 3.x als auch in Python 2.6 / 2.7 funktionieren. Hier ist es wieder mit dem vollständigen Beispiel:

import io
import numpy
x = "1 3\n 4.5 8"
numpy.genfromtxt(io.BytesIO(x.encode()))

Ausgabe:

array([[ 1. ,  3. ],
       [ 4.5,  8. ]])

Erklärung für Python 3.x:

  • numpy.genfromtxt Nimmt einen Bytestream (ein dateiähnliches Objekt, das anstelle von Unicode als Byte interpretiert wird).
  • io.BytesIONimmt eine Byte-Zeichenfolge und gibt einen Byte-Stream zurück. io.StringIOAuf der anderen Seite würde eine Unicode-Zeichenfolge verwendet und ein Unicode-Stream zurückgegeben.
  • x wird ein String-Literal zugewiesen, das in Python 3.x ein Unicode-String ist.
  • encode()Nimmt die Unicode-Zeichenfolge xund erstellt daraus eine Byte-Zeichenfolge, wodurch io.BytesIOein gültiges Argument angegeben wird.

Der einzige Unterschied für Python 2.6 / 2.7 besteht darin, dass xes sich um eine Byte-Zeichenfolge handelt (vorausgesetzt, sie from __future__ import unicode_literalswird nicht verwendet), die dann encode()die Byte-Zeichenfolge verwendet xund trotzdem dieselbe Byte-Zeichenfolge daraus erstellt. Das Ergebnis ist also dasselbe.


Da dies eine der beliebtesten Fragen von SO ist StringIO, finden Sie hier weitere Erläuterungen zu den Importanweisungen und den verschiedenen Python-Versionen.

Hier sind die Klassen, die einen String nehmen und einen Stream zurückgeben:

  • io.BytesIO(Python 2.6, 2.7 und 3.x) - Nimmt eine Byte-Zeichenfolge. Gibt einen Bytestream zurück.
  • io.StringIO(Python 2.6, 2.7 und 3.x) - Nimmt eine Unicode-Zeichenfolge. Gibt einen Unicode-Stream zurück.
  • StringIO.StringIO(Python 2.x) - Nimmt eine Byte-Zeichenfolge oder eine Unicode-Zeichenfolge. Wenn Byte-String, wird ein Byte-Stream zurückgegeben. Wenn Unicode-Zeichenfolge, wird ein Unicode-Stream zurückgegeben.
  • cStringIO.StringIO(Python 2.x) - Schnellere Version von StringIO.StringIO, kann jedoch keine Unicode-Zeichenfolgen akzeptieren, die Nicht-ASCII-Zeichen enthalten.

Beachten Sie, dass StringIO.StringIOals importiert from StringIO import StringIOund dann als verwendet wird StringIO(...). Entweder das, oder du tust es import StringIOund verwendest es dann StringIO.StringIO(...). Der Modulname und der Klassenname sind zufällig identisch. Es ist ähnlich datetimeso.

Was ist zu verwenden, abhängig von Ihren unterstützten Python-Versionen:

  • Wenn Sie nur Python 3.x unterstützen: Verwenden Sie einfach io.BytesIOoder io.StringIOabhängig davon, mit welcher Art von Daten Sie arbeiten.

  • Wenn Sie sowohl Python 2.6 / 2.7 als auch 3.x unterstützen oder versuchen, Ihren Code von 2.6 / 2.7 auf 3.x umzustellen: Die einfachste Option ist weiterhin die Verwendung von io.BytesIOoder io.StringIO. Obwohl StringIO.StringIOflexibel ist und daher für 2.6 / 2.7 bevorzugt erscheint, könnte diese Flexibilität Fehler maskieren, die sich in 3.x manifestieren. Zum Beispiel hatte ich Code, der verwendet wurde StringIO.StringIOoder io.StringIOvon der Python-Version abhängt, aber ich habe tatsächlich eine Byte-Zeichenfolge übergeben. Als ich zum Testen in Python 3.x kam, schlug dies fehl und musste behoben werden.

    Ein weiterer Vorteil der Verwendung io.StringIOist die Unterstützung für universelle Newlines. Wenn Sie das Schlüsselwort Argument übergeben newline=''in io.StringIO, wird es in der Lage sein , Zeilen aufgeteilt auf alle \n, \r\noder \r. Ich fand, dass StringIO.StringIOdas besonders auffallen würde \r.

    Beachten Sie, dass , wenn Sie importieren BytesIOoder StringIOaus six, erhalten Sie StringIO.StringIOin Python 2.x und die entsprechende Klasse von ioin Python 3.x Wenn Sie der Einschätzung meiner vorherigen Absätze zustimmen, ist dies tatsächlich ein Fall, in dem Sie vermeiden sixund iostattdessen einfach importieren sollten .

  • Wenn Sie Python 2.5 oder niedriger und 3.x unterstützen: Sie benötigen StringIO.StringIO2.5 oder niedriger, also können Sie es auch verwenden six. Beachten Sie jedoch, dass es im Allgemeinen sehr schwierig ist, sowohl 2.5 als auch 3.x zu unterstützen. Daher sollten Sie in Betracht ziehen, Ihre niedrigste unterstützte Version auf 2.6 zu erhöhen, wenn dies überhaupt möglich ist.


7

Damit Beispiele von hier mit Python 3.5.2 funktionieren, können Sie wie folgt umschreiben:

import io
data =io.BytesIO(b"1, 2, 3\n4, 5, 6") 
import numpy
numpy.genfromtxt(data, delimiter=",")

Der Grund für die Änderung kann sein, dass sich der Inhalt einer Datei in Daten (Bytes) befindet, die erst dann Text erzeugen, wenn sie irgendwie dekodiert wurden. genfrombyteskann ein besserer Name sein als genfromtxt.


-4

Versuche dies

aus StringIO StringIO importieren

x = "1 3 \ n 4,5 8"

numpy.genfromtxt (StringIO (x))

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.