web-dev-qa-db-fra.com

StringIO en Python3

J'utilise Python 3.2.1 et je ne peux pas importer le module StringIO. J'utilise io.StringIO et cela fonctionne, mais je ne peux pas l'utiliser avec numpy 'genfromtxt comme ceci:

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

Je reçois l'erreur suivante:

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

et quand j'écris import StringIO il dit

ImportError: No module named 'StringIO'
368
user1591744

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

De Quoi de neuf dans Python 3. :

Les modules StringIO et cStringIO ont disparu. Importez plutôt le module io et utilisez io.StringIO ou io.BytesIO pour le texte et les données, respectivement.

.


Une méthode éventuellement utile pour corriger du code Python 2 à fonctionner également dans Python 3 (mise en garde):

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

Remarque: Cet exemple peut être tangent au problème principal de la question et n'est inclus que comme élément à prendre en compte lors de la résolution générique du module manquant StringIO. Pour une solution plus directe le message TypeError: Can't convert 'bytes' object to str implicitly, voir cette réponse .

611
nobar

Dans mon cas j'ai utilisé:

from io import StringIO
112
Kamesh Jungi

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

numpy.genfromtxt(io.BytesIO(x.encode()))
64
Roman Shapovalov

Merci OP pour votre question et Roman pour votre réponse. J'ai dû chercher un peu pour trouver ceci; 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 plus:

dtype = "| Sx", où x = l'un quelconque 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; le premier signifie que le tableau contient des chaînes de longueur 1, les secondes de longueur 2. ..."

23
Victoria Stuart

Vous pouvez utiliser le StringIO du module six :

import six
import numpy

x = "1 3\n 4.5 8"
numpy.genfromtxt(six.StringIO(x))
17
Tiago Coutinho

Le code de Roman Shapovalov devrait fonctionner dans Python 3.x ainsi que Python 2.6/2.7. Le voici encore avec l'exemple complet:

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

Sortie:

_array([[ 1. ,  3. ],
       [ 4.5,  8. ]])
_

Explication de 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.BytesIO_ prend une chaîne d'octets et renvoie un flux d'octets. _io.StringIO_, d'autre part, prendrait une chaîne Unicode et renverrait un flux Unicode.
  • x se voit attribuer un littéral de chaîne qui, dans Python 3.x, est une chaîne Unicode.
  • encode() prend la chaîne Unicode x et en fait une chaîne d'octets, donnant ainsi à _io.BytesIO_ un argument valide.

La seule différence entre Python 2.6/2.7 est que x est une chaîne d'octets (en supposant que _from __future__ import unicode_literals_ n'est pas utilisé), puis encode() prend la chaîne d'octets x et continue de le faire. chaîne d'octets hors de celui-ci. Donc, le résultat est le même.


Comme il s’agit de l’une des questions les plus courantes de SO concernant 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, retourne un flux Unicode.
  • cStringIO.StringIO (Python 2.x) - Version plus rapide de _StringIO.StringIO_, mais ne peut pas prendre de chaînes Unicode contenant des caractères non-ASCII.

Notez que _StringIO.StringIO_ est importé en tant que _from StringIO import StringIO_, puis utilisé en tant que StringIO(...). Soit ça, soit vous faites _import StringIO_ puis utilisez StringIO.StringIO(...). Le nom du module et le nom de la classe sont les mêmes. C'est semblable à datetime de cette façon.

Quoi utiliser, en fonction de vos versions Python prises en charge:

  • Si vous ne supportez que Python 3.x: Utilisez simplement _io.BytesIO_ ou _io.StringIO_ en fonction de quel type des données avec lesquelles vous travaillez.

  • Si vous prenez en charge les deux Python 2.6/2.7 et 3.x, ou tentez de faire passer votre code de 2.6/2.7 à 3.x: L'option la plus simple reste d'utiliser _io.BytesIO_ ou _io.StringIO_. Bien que _StringIO.StringIO_ soit flexible et semble donc préféré pour 2.6/2.7, cette flexibilité pourrait masquer les bogues qui se manifesteront dans 3.x. Par exemple, j'avais un code qui utilisait _StringIO.StringIO_ ou _io.StringIO_ en fonction de la version Python, mais je transmettais en fait une chaîne d'octets.Python 3.x, il a échoué et a dû être corrigé.

    Un autre avantage de l'utilisation de _io.StringIO_ est la prise en charge des nouvelles lignes universelles. Si vous transmettez le mot clé argument _newline=''_ à _io.StringIO_, il sera en mesure de fractionner les lignes de l'un des éléments _\n_, _\r\n_ ou _\r_. J'ai trouvé que _StringIO.StringIO_ retomberait sur _\r_ en particulier.

    Notez que si vous importez BytesIO ou StringIO from six , vous obtenez _StringIO.StringIO_ dans Python 2.x et la classe appropriée de io dans Python. 3.x. Si vous êtes d’accord avec l’évaluation des paragraphes précédents, c’est en fait un cas dans lequel vous devriez éviter six et simplement importer à partir de io à la place.

  • Si vous supportez Python 2.5 ou moins et 3.x: , vous aurez besoin de _StringIO.StringIO_ pour 2.5 ou moins, vous pouvez donc aussi utiliser six. Cependant, sachez qu’il est généralement très difficile de prendre en charge les versions 2.5 et 3.x. Vous devez donc envisager de remplacer la version la moins prise en charge par la version 2.6 si possible.

15
S. Kirby

Pour créer des exemples à partir de ici travailler 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 est sous forme de données (octets) qui ne créent pas de texte tant qu'elles ne sont pas décodées. genfrombytes peut être un meilleur nom que genfromtxt.

6
Pierre ALBARÈDE