StringIO in Python3


474

Sto usando Python 3.2.1 e non riesco a importare il StringIOmodulo. Io lo uso io.StringIOe funziona, ma non posso usarlo con numpy's genfromtxtcome questo:

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

Ottengo il seguente errore:

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

e quando scrivo import StringIOdice

ImportError: No module named 'StringIO'

Risposte:


774

quando scrivo import StringIO dice che non esiste tale modulo.

Dalle novità di Python 3.0 :

I moduli StringIOe cStringIOsono spariti. Invece, importa il io modulo e usa io.StringIOo rispettivamente io.BytesIOper testo e dati.

.


Un metodo forse utile per correggere un po 'di codice Python 2 per funzionare anche in Python 3 (caveat emptor):

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

Nota: questo esempio può essere tangente al problema principale della domanda ed è incluso solo come qualcosa da considerare quando si indirizza genericamente il StringIOmodulo mancante . Per una soluzione più diretta il messaggio TypeError: Can't convert 'bytes' object to str implicitly, vedere questa risposta .


13
Vale la pena ricordare che questi non sono gli stessi, quindi puoi finire con TypeErrors (argomento stringa previsto, ottenuto 'byte') se apporti questa modifica in modo isolato. Devi distinguere attentamente btyes e str (unicode) in Python 3.
Andy Hayden

7
Per i newb come me: da io import StringIO significa che lo chiami come StringIO (), non io.StringIO ().
Noumenon,

11
Come essere effettivamente compatibile con Python 2 e 3: solofrom io import StringIO
Oleh Prypin l'

8
QUESTO È SEMPLICEMENTE SBAGLIATO per numpy.genfromtxt () in Python 3. Fare riferimento alla risposta di Roman Shapovalov.
Bill Huang

2
@nobar: quest'ultimo. La domanda originale usa python 3.x, da cui il modulo StringIOè andato e from io import BytesIOdovrebbe invece essere applicato. Messo alla prova su Python 3.5 @ eclipse pyDev + win7 x64. Per favore fatemi sapere se ho sbagliato grazie.
Bill Huang


71

Su Python 3 si numpy.genfromtxtaspetta un flusso di byte. Utilizza il seguente:

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

24

Grazie OP per la tua domanda e Roman per la tua risposta. Ho dovuto cercare un po 'per trovare questo; Spero che quanto segue aiuti gli altri.

Python 2.7

Vedi: 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.]]
"""

A parte:

dtype = "| Sx", dove x = uno qualsiasi di {1, 2, 3, ...}:

dtypes. Differenza tra S1 e S2 in Python

"Le stringhe | S1 e | S2 sono descrittori di tipi di dati; il primo significa che l'array contiene stringhe di lunghezza 1, il secondo di lunghezza 2. ..."



17

Il codice di Roman Shapovalov dovrebbe funzionare in Python 3.xe in Python 2.6 / 2.7. Eccolo di nuovo con l'esempio completo:

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

Produzione:

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

Spiegazione per Python 3.x:

  • numpy.genfromtxt accetta un flusso di byte (un oggetto simile a un file interpretato come byte anziché Unicode).
  • io.BytesIOaccetta una stringa di byte e restituisce un flusso di byte. io.StringIO, d'altra parte, prenderebbe una stringa Unicode e restituirebbe un flusso Unicode.
  • x riceve una stringa letterale, che in Python 3.x è una stringa Unicode.
  • encode()prende la stringa Unicode xe ne ricava una stringa di byte, fornendo così io.BytesIOun argomento valido.

L'unica differenza per Python 2.6 / 2.7 è che xè una stringa di byte (supponendo che from __future__ import unicode_literalsnon sia usata), quindi encode()prende la stringa di byte xe ne ricava comunque la stessa stringa di byte. Quindi il risultato è lo stesso.


Poiché questa è una delle domande più popolari di SO in merito StringIO, ecco alcune spiegazioni in più sulle dichiarazioni di importazione e sulle diverse versioni di Python.

Ecco le classi che prendono una stringa e restituiscono un flusso:

  • io.BytesIO(Python 2.6, 2.7 e 3.x) - Accetta una stringa di byte. Restituisce un flusso di byte.
  • io.StringIO(Python 2.6, 2.7 e 3.x) - Accetta una stringa Unicode. Restituisce un flusso Unicode.
  • StringIO.StringIO(Python 2.x): accetta una stringa di byte o una stringa Unicode. Se stringa di byte, restituisce un flusso di byte. Se stringa Unicode, restituisce un flusso Unicode.
  • cStringIO.StringIO(Python 2.x) - Versione più veloce di StringIO.StringIO, ma non può accettare stringhe Unicode che contengono caratteri non ASCII.

Si noti che StringIO.StringIOviene importato come from StringIO import StringIO, quindi utilizzato come StringIO(...). O quello, o lo fai import StringIOe poi usi StringIO.StringIO(...). Il nome del modulo e il nome della classe sono sempre gli stessi. È simile a datetimequello.

Cosa usare, a seconda delle versioni di Python supportate:

  • Se supporti solo Python 3.x: usa io.BytesIOo io.StringIOdipende dal tipo di dati con cui stai lavorando.

  • Se si supportano sia Python 2.6 / 2.7 e 3.x, o si sta tentando di trasferire il codice da 2.6 / 2.7 a 3.x: l'opzione più semplice è ancora usare io.BytesIOo io.StringIO. Sebbene StringIO.StringIOsia flessibile e quindi sembra preferito per 2.6 / 2.7, tale flessibilità potrebbe mascherare i bug che si manifesteranno in 3.x. Ad esempio, avevo un po 'di codice che utilizzava StringIO.StringIOo io.StringIOdipendeva dalla versione di Python, ma in realtà stavo passando una stringa di byte, quindi quando ho avuto modo di provarlo in Python 3.x non è riuscito e ha dovuto essere riparato.

    Un altro vantaggio dell'utilizzo io.StringIOè il supporto per newline universali. Se si passa l'argomento chiave newline=''in io.StringIO, sarà in grado di dividere le linee su uno qualsiasi dei \n, \r\no \r. Ho scoperto che StringIO.StringIOsarebbe inciampato \rin particolare.

    Si noti che se si importa BytesIOo StringIOda six, si ottiene StringIO.StringIOin Python 2.xe la classe appropriata da ioin Python 3.x. Se sei d'accordo con la valutazione dei miei paragrafi precedenti, questo è in realtà un caso in cui dovresti evitare sixe semplicemente importare ioinvece.

  • Se si supporta Python 2.5 o versioni precedenti e 3.x: è necessario StringIO.StringIOdisporre di 2.5 o versioni precedenti, quindi è consigliabile utilizzarle six. Ma renditi conto che in genere è molto difficile supportare sia la 2.5 che la 3.x, quindi dovresti considerare di portare la versione più bassa supportata alla 2.6 se possibile.


7

Per far funzionare esempi da qui con Python 3.5.2, puoi riscrivere come segue:

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

Il motivo della modifica potrebbe essere che il contenuto di un file è in dati (byte) che non creano testo fino a quando non vengono decodificati in qualche modo. genfrombytespotrebbe essere un nome migliore di genfromtxt.


-4

prova questo

da StringIO importa StringIO

x = "1 3 \ n 4.5 8"

numpy.genfromtxt (StringIO (x))

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.