StringIO em Python3


474

Estou usando o Python 3.2.1 e não consigo importar o StringIOmódulo. Eu uso io.StringIOe funciona, mas não posso usá-lo com numpyo genfromtxtseguinte:

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

Estou tendo o erro a seguir:

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

e quando escrevo import StringIOdiz

ImportError: No module named 'StringIO'

Respostas:


774

Quando escrevo Import StringIO, ele diz que não existe esse módulo.

Do que há de novo no Python 3.0 :

Os módulos StringIOe cStringIOse foram. Em vez disso, importe o io módulo e use io.StringIOou io.BytesIOpara texto e dados, respectivamente.

.


Um método possivelmente útil para consertar algum código Python 2 para também funcionar no Python 3 (advertência):

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

Nota: Este exemplo pode ser tangencial à questão principal da pergunta e é incluído apenas como algo a considerar ao tratar genericamente o StringIOmódulo ausente . Para uma solução mais direta, a mensagem TypeError: Can't convert 'bytes' object to str implicitly, consulte esta resposta .


13
Vale mencionar que esses não são os mesmos; portanto, você pode terminar com TypeErrors (argumento de string esperado, obteve 'bytes') se fizer essa alteração isoladamente. Você precisa distinguir cuidadosamente btyes e str (unicode) em python 3.
Andy Hayden

7
Para iniciantes como eu: de io import StringIO significa que você o chama como StringIO (), não io.StringIO ().
Noumenon

11
Como realmente ser compatível com Python 2 e 3: apenasfrom io import StringIO
Oleh Prypin

8
ISSO É SIMPLESMENTE ERRADO para numpy.genfromtxt () no python 3. Consulte a resposta de Roman Shapovalov.
Bill Huang

2
@nobar: O último. A pergunta original usa python 3.x, da qual o módulo StringIOse foi e from io import BytesIOdeve ser aplicado. Testei-me em python 3.5 @ eclipse pyDev + win7 x64. Entre em contato se estiver errado, obrigado.
Bill Huang


70

No Python 3, numpy.genfromtxtespera-se um fluxo de bytes. Use o seguinte:

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

24

Obrigado OP pela sua pergunta e Roman pela sua resposta. Eu tive que procurar um pouco para encontrar isso; Espero que o seguinte ajude outras pessoas.

Python 2.7

Consulte: 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, de lado:

dtype = "| Sx", em que x = qualquer um dos {1, 2, 3, ...}:

tipos. Diferença entre S1 e S2 em Python

"As strings | S1 e | S2 são descritores de tipo de dados; o primeiro significa que o array contém strings de comprimento 1, o segundo de comprimento 2. ..."



17

O código de Roman Shapovalov deve funcionar no Python 3.x e no Python 2.6 / 2.7. Aqui está novamente com o exemplo completo:

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

Resultado:

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

Explicação para o Python 3.x:

  • numpy.genfromtxt utiliza um fluxo de bytes (um objeto parecido com um arquivo interpretado como bytes em vez de Unicode).
  • io.BytesIOpega uma sequência de bytes e retorna um fluxo de bytes. io.StringIO, por outro lado, pegaria uma string Unicode e retornaria um fluxo Unicode.
  • x recebe uma string literal, que no Python 3.x é uma string Unicode.
  • encode()pega a string Unicode xe cria uma string de bytes, fornecendo io.BytesIOum argumento válido.

A única diferença para o Python 2.6 / 2.7 é que xé uma sequência de bytes (supondo que from __future__ import unicode_literalsnão seja usada) e, encode()em seguida, pega a sequência de bytes xe ainda cria a mesma sequência de bytes. Então o resultado é o mesmo.


Como essa é uma das perguntas mais populares da SO StringIO, aqui estão mais algumas explicações sobre as instruções de importação e as diferentes versões do Python.

Aqui estão as classes que pegam uma string e retornam um fluxo:

  • io.BytesIO(Python 2.6, 2.7 e 3.x) - Aceita uma sequência de bytes. Retorna um fluxo de bytes.
  • io.StringIO(Python 2.6, 2.7 e 3.x) - utiliza uma string Unicode. Retorna um fluxo Unicode.
  • StringIO.StringIO(Python 2.x) - Aceita uma sequência de bytes ou Unicode. Se sequência de bytes, retorna um fluxo de bytes. Se sequência Unicode, retorna um fluxo Unicode.
  • cStringIO.StringIO(Python 2.x) - Versão mais rápida StringIO.StringIO, mas não aceita sequências de caracteres Unicode que contêm caracteres não ASCII.

Observe que StringIO.StringIOé importado como from StringIO import StringIOe usado como StringIO(...). Ou isso, ou você faz import StringIOe depois usa StringIO.StringIO(...). O nome do módulo e o nome da classe são os mesmos. É semelhante a datetimeesse caminho.

O que usar, dependendo das versões suportadas do Python:

  • Se você suporta apenas o Python 3.x: use io.BytesIOou io.StringIOdependendo de que tipo de dados você está trabalhando.

  • Se você suporta o Python 2.6 / 2.7 e 3.x, ou está tentando fazer a transição do seu código de 2.6 / 2.7 para 3.x: A opção mais fácil ainda é usar io.BytesIOou io.StringIO. Embora StringIO.StringIOseja flexível e, portanto, pareça preferível para 2.6 / 2.7, essa flexibilidade pode mascarar os erros que se manifestarão na 3.x. Por exemplo, eu tinha algum código que usava StringIO.StringIOou io.StringIOdependia da versão do Python, mas na verdade estava passando uma sequência de bytes, por isso, quando comecei a testá-lo no Python 3.x, ele falhou e teve que ser corrigido.

    Outra vantagem do uso io.StringIOé o suporte para novas linhas universais. Se você passar a palavra-chave argumento newline=''para io.StringIO, ele será capaz de dividir as linhas em qualquer um \n, \r\nou \r. Eu descobri que isso StringIO.StringIOiria tropeçar \rem particular.

    Observe que, se você importar BytesIOou StringIOde six, entra StringIO.StringIOno Python 2.xe a classe apropriada iono Python 3.x. Se você concorda com a avaliação dos parágrafos anteriores, esse é realmente um caso em que você deve evitar sixe apenas importar io.

  • Se você suporta Python 2.5 ou inferior e 3.x: você precisará StringIO.StringIOde 2.5 ou inferior, então você pode usá-lo six. Mas saiba que geralmente é muito difícil oferecer suporte tanto ao 2.5 quanto ao 3.x, portanto, você deve considerar elevar sua versão mais baixa suportada para 2.6, se possível.


7

Para fazer com que os exemplos daqui funcionem com o Python 3.5.2, você pode reescrever da seguinte maneira:

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

O motivo da alteração pode ser que o conteúdo de um arquivo esteja em dados (bytes) que não produzem texto até serem decodificados de alguma forma. genfrombytespode ser um nome melhor que genfromtxt.


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.