StringIO en Python3


474

Estoy usando Python 3.2.1 y no puedo importar el StringIOmódulo. Yo uso io.StringIOy funciona, pero no puedo usarlo con numpy's genfromtxtcomo este:

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

Obtuve el siguiente error:

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

y cuando escribo import StringIOdice

ImportError: No module named 'StringIO'

Respuestas:


774

cuando escribo import StringIO dice que no existe tal módulo.

De lo nuevo en Python 3.0 :

Los módulos StringIOy cStringIOse han ido. En su lugar, importe el io módulo y use io.StringIOo io.BytesIOpara texto y datos respectivamente.

.


Un método posiblemente útil para arreglar algún código de Python 2 para que también funcione en Python 3 (advertencia de advertencia):

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

Nota: Este ejemplo puede ser tangencial al tema principal de la pregunta y se incluye solo como algo a tener en cuenta al abordar genéricamente el StringIOmódulo que falta . Para una solución más directa al mensaje TypeError: Can't convert 'bytes' object to str implicitly, vea esta respuesta .


13
Vale la pena mencionar que estos no son lo mismo, por lo que puede terminar con TypeErrors (se espera un argumento de cadena, obtuvo 'bytes') si realiza este cambio de forma aislada. Debe distinguir cuidadosamente btyes y str (unicode) en python 3.
Andy Hayden

77
Para novatos como yo: desde io import StringIO significa que lo llamas como StringIO (), no io.StringIO ().
Noumenon

11
Cómo ser realmente compatible con Python 2 y 3: solofrom io import StringIO
Oleh Prypin

8
ESTO ES SIMPLEMENTE INCORRECTO para numpy.genfromtxt () en python 3. Consulte la respuesta de Roman Shapovalov.
Bill Huang

2
@nobar: El último. La pregunta original usa python 3.x, del cual el módulo StringIOdesapareció y from io import BytesIOdebería aplicarse en su lugar. Probado en python 3.5 @ eclipse pyDev + win7 x64. Por favor, avíseme si me equivoqué, gracias.
Bill Huang


71

En Python 3 numpy.genfromtxtespera una secuencia de bytes. Use lo siguiente:

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

24

Gracias OP por tu pregunta y Roman por tu respuesta. Tuve que buscar un poco para encontrar esto; Espero que lo siguiente ayude a otros.

Python 2.7

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

Aparte:

dtype = "| Sx", donde x = cualquiera de {1, 2, 3, ...}:

dtypes Diferencia entre S1 y S2 en Python

"Las cadenas | S1 y | S2 son descriptores de tipo de datos; el primero significa que la matriz contiene cadenas de longitud 1, la segunda de longitud 2. ..."



17

El código de Roman Shapovalov debería funcionar en Python 3.x y Python 2.6 / 2.7. Aquí está de nuevo con el ejemplo completo:

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

Salida:

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

Explicación para Python 3.x:

  • numpy.genfromtxt toma una secuencia de bytes (un objeto similar a un archivo interpretado como bytes en lugar de Unicode).
  • io.BytesIO toma una cadena de bytes y devuelve una secuencia de bytes. io.StringIO, por otro lado, tomaría una cadena Unicode y devolvería una secuencia Unicode.
  • x se le asigna un literal de cadena, que en Python 3.x es una cadena Unicode.
  • encode()toma la cadena Unicode xy crea una cadena de bytes, dando así io.BytesIOun argumento válido.

La única diferencia para Python 2.6 / 2.7 es que xes una cadena de bytes (suponiendo from __future__ import unicode_literalsque no se use), y luego encode()toma la cadena de bytes xy aún hace la misma cadena de bytes. Entonces el resultado es el mismo.


Como esta es una de las preguntas más populares sobre SO StringIO, aquí hay más explicaciones sobre las declaraciones de importación y las diferentes versiones de Python.

Estas son las clases que toman una cadena y devuelven una secuencia:

  • io.BytesIO(Python 2.6, 2.7 y 3.x): toma una cadena de bytes. Devuelve una secuencia de bytes.
  • io.StringIO(Python 2.6, 2.7 y 3.x): toma una cadena Unicode. Devuelve una secuencia Unicode.
  • StringIO.StringIO(Python 2.x): toma una cadena de bytes o una cadena Unicode. Si la cadena de bytes, devuelve una secuencia de bytes. Si es una cadena Unicode, devuelve una secuencia Unicode.
  • cStringIO.StringIO(Python 2.x): versión más rápida de StringIO.StringIO, pero no puede tomar cadenas Unicode que contengan caracteres no ASCII.

Tenga en cuenta que StringIO.StringIOse importa como from StringIO import StringIO, luego se usa como StringIO(...). O eso, o lo haces import StringIOy luego lo usas StringIO.StringIO(...). El nombre del módulo y el nombre de la clase son los mismos. Es similar a datetimeeso.

Qué usar, dependiendo de sus versiones de Python compatibles:

  • Si solo es compatible con Python 3.x: simplemente use io.BytesIOo io.StringIOdependiendo de qué tipo de datos esté trabajando.

  • Si es compatible con Python 2.6 / 2.7 y 3.x, o está tratando de hacer la transición de su código de 2.6 / 2.7 a 3.x: la opción más fácil aún es usar io.BytesIOo io.StringIO. Aunque StringIO.StringIOes flexible y, por lo tanto, parece preferible para 2.6 / 2.7, esa flexibilidad podría enmascarar errores que se manifestarán en 3.x. Por ejemplo, tenía un código que usaba StringIO.StringIOo io.StringIOdependía de la versión de Python, pero en realidad estaba pasando una cadena de bytes, así que cuando pude probarlo en Python 3.x falló y tuve que arreglarlo.

    Otra ventaja de usar io.StringIOes el soporte para líneas nuevas universales. Si pasa el argumento de palabra clave newline=''en io.StringIO, será capaz de dividir las líneas en cualquiera de \n, \r\no \r. Descubrí que StringIO.StringIOtropezaría \ren particular.

    Tenga en cuenta que si importa BytesIOo StringIOdesde six, obtiene StringIO.StringIOPython 2.xy la clase apropiada ioen Python 3.x. Si está de acuerdo con la evaluación de mis párrafos anteriores, este es realmente un caso en el que debe evitar sixy simplemente importar desde su iolugar.

  • Si es compatible con Python 2.5 o inferior y 3.x: necesitará StringIO.StringIO2.5 o inferior, por lo que podría usarlo six. Pero tenga en cuenta que, en general, es muy difícil admitir 2.5 y 3.x, por lo que debería considerar subir su versión más baja a 2.6 si es posible.


7

Para que los ejemplos de aquí funcionen con Python 3.5.2, puede volver a escribir de la siguiente manera:

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

La razón del cambio puede ser que el contenido de un archivo está en datos (bytes) que no forman texto hasta que se decodifican de alguna manera. genfrombytespuede ser un mejor nombre que genfromtxt.


Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.