StringIO en Python3


474

J'utilise Python 3.2.1 et je ne peux pas importer le StringIOmodule. Je l' utilise io.StringIOet il fonctionne, mais je ne peux pas l' utiliser avec numpy« s genfromtxtcomme celui - ci:

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

J'obtiens l'erreur suivante:

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

et quand j'écris import StringIOça dit

ImportError: No module named 'StringIO'

Réponses:


774

quand j'écris import StringIO, il dit qu'il n'y a pas un tel module.

À partir des nouveautés de Python 3.0 :

Les modules StringIOet cStringIOont disparu. À la place, importez le io module et utilisez respectivement io.StringIOou io.BytesIOpour le texte et les données.

.


Une méthode éventuellement utile pour corriger du code Python 2 pour qu'il fonctionne également en Python 3 (caveat emptor):

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

Remarque: Cet exemple peut être tangentiel au problème principal de la question et n'est inclus que comme quelque chose à considérer lors de l'adressage générique du StringIOmodule manquant . Pour une solution plus directe du message TypeError: Can't convert 'bytes' object to str implicitly, consultez cette réponse .


13
Il convient de mentionner que ce ne sont pas les mêmes, vous pouvez donc vous retrouver avec TypeErrors (argument de chaîne attendu, obtenu «octets») si vous effectuez cette modification de manière isolée. Vous devez soigneusement distinguer les btyes et les str (unicode) en python 3.
Andy Hayden

7
Pour les newbs comme moi: depuis io import StringIO signifie que vous l'appelez StringIO (), pas io.StringIO ().
Noumenon

11
Comment être réellement compatible avec Python 2 et 3: justefrom io import StringIO
Oleh Prypin

8
C'EST SIMPLEMENT ERRONÉ pour numpy.genfromtxt () en python 3. Veuillez vous référer à la réponse de Roman Shapovalov.
Bill Huang

2
@nobar: Ce dernier. La question d'origine utilise python 3.x, d'où le module a StringIOdisparu et from io import BytesIOdoit être appliqué à la place. Je me suis testé sur python 3.5 @ eclipse pyDev + win7 x64. S'il vous plaît laissez-moi savoir si je me suis trompé merci.
Bill Huang


71

Sur Python 3 numpy.genfromtxtattend un flux d'octets. Utilisez le suivant:

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

24

Merci OP pour votre question et Roman pour votre réponse. J'ai dû chercher un peu pour trouver cela; J'espère que ce qui suit aide les autres.

Python 2.7

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

De côté:

dtype = "| Sx", où x = l'un des {1, 2, 3, ...}:

dtypes. Différence entre S1 et S2 en Python

"Les chaînes | S1 et | S2 sont des descripteurs de type de données; la première signifie que le tableau contient des chaînes de longueur 1, la seconde de longueur 2. ..."



17

Le code de Roman Shapovalov devrait fonctionner aussi bien en Python 3.x qu'en Python 2.6 / 2.7. Le voici à nouveau avec l'exemple complet:

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

Production:

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

Explication pour Python 3.x:

  • numpy.genfromtxt prend un flux d'octets (un objet de type fichier interprété comme des octets au lieu d'Unicode).
  • io.BytesIOprend une chaîne d'octets et retourne un flux d'octets. io.StringIO, d'autre part, prendrait une chaîne Unicode et retournerait un flux Unicode.
  • x obtient un littéral de chaîne, qui dans Python 3.x est une chaîne Unicode.
  • encode()prend la chaîne Unicode xet en fait une chaîne d'octets, donnant ainsi io.BytesIOun argument valide.

La seule différence pour Python 2.6 / 2.7 est qu'il xs'agit d'une chaîne d'octets (en supposant qu'elle from __future__ import unicode_literalsn'est pas utilisée), puis encode()prend la chaîne d'octets xet en fait toujours la même chaîne d'octets. Le résultat est donc le même.


Comme il s'agit de l'une des questions les plus populaires de SO StringIO, voici quelques explications supplémentaires sur les instructions d'importation et les différentes versions de Python.

Voici les classes qui prennent une chaîne et retournent un flux:

  • io.BytesIO(Python 2.6, 2.7 et 3.x) - Prend une chaîne d'octets. Renvoie un flux d'octets.
  • io.StringIO(Python 2.6, 2.7 et 3.x) - Prend une chaîne Unicode. Renvoie un flux Unicode.
  • StringIO.StringIO(Python 2.x) - Prend une chaîne d'octets ou une chaîne Unicode. Si chaîne d'octets, retourne un flux d'octets. Si chaîne Unicode, renvoie un flux Unicode.
  • cStringIO.StringIO(Python 2.x) - Version plus rapide de StringIO.StringIO, mais ne peut pas accepter des chaînes Unicode qui contiennent des caractères non ASCII.

Notez qu'il StringIO.StringIOest importé en tant que from StringIO import StringIO, puis utilisé en tant que StringIO(...). Soit cela, soit vous le faites import StringIO, puis vous l'utilisez StringIO.StringIO(...). Il se trouve que le nom du module et le nom de la classe sont identiques. C'est comme datetimeça.

Ce qu'il faut utiliser, selon les versions de Python prises en charge:

  • Si vous ne supportez que Python 3.x: utilisez simplement io.BytesIOou io.StringIOselon le type de données avec lesquelles vous travaillez.

  • Si vous prenez en charge Python 2.6 / 2.7 et 3.x, ou essayez de faire passer votre code de 2.6 / 2.7 à 3.x: l' option la plus simple est toujours d'utiliser io.BytesIOou io.StringIO. Bien qu'elle StringIO.StringIOsoit flexible et semble donc préférée pour 2.6 / 2.7, cette flexibilité pourrait masquer les bogues qui se manifesteront dans 3.x. Par exemple, j'avais du code qui utilisait StringIO.StringIOou io.StringIOdépendait de la version de Python, mais je passais en fait une chaîne d'octets, donc quand je me suis mis à le tester dans Python 3.x, il a échoué et a dû être corrigé.

    Un autre avantage de l'utilisation io.StringIOest la prise en charge des sauts de ligne universels. Si vous passez l'argument mot - clé newline=''dans io.StringIO, il sera en mesure de diviser des lignes sur l' une \n, \r\nou \r. J'ai trouvé que StringIO.StringIOcela se déclencherait \ren particulier.

    Notez que si vous importez BytesIOou à StringIOpartir de six, vous obtenez StringIO.StringIOdans Python 2.x et la classe appropriée iodans Python 3.x. Si vous êtes d'accord avec l'évaluation de mes paragraphes précédents, il s'agit en fait d'un cas dans lequel vous devriez éviter sixet simplement importer à la ioplace.

  • Si vous prenez en charge Python 2.5 ou inférieur et 3.x: vous aurez besoin StringIO.StringIOde 2.5 ou inférieur, vous pouvez donc aussi bien l'utiliser six. Mais sachez qu'il est généralement très difficile de prendre en charge les versions 2.5 et 3.x, vous devriez donc envisager de transférer votre version prise en charge la plus basse vers 2.6 si possible.


7

Pour que les exemples d' ici fonctionnent avec Python 3.5.2, vous pouvez réécrire comme suit:

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

La raison de la modification peut être que le contenu d'un fichier se trouve dans des données (octets) qui ne font pas de texte avant d'être décodées d'une manière ou d'une autre. genfrombytespeut être un meilleur nom que genfromtxt.


En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.