StringIO w Python3


473

Korzystam z Python 3.2.1 i nie mogę zaimportować StringIOmodułu. Używam io.StringIOi działa, ale nie można go używać z numpy„s genfromtxtjak to:

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

Otrzymuję następujący błąd:

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

a kiedy piszę import StringIO, mówi

ImportError: No module named 'StringIO'

Odpowiedzi:


771

kiedy piszę import StringIO, mówi, że nie ma takiego modułu.

Od Co nowego w Python 3.0 :

StringIOI cStringIOmoduły zostaną usunięte. Zamiast tego zaimportuj io moduł i użyj odpowiednio io.StringIOlub io.BytesIOdla tekstu i danych.

.


Prawdopodobnie przydatna metoda naprawiania kodu Pythona 2, aby działał również w Pythonie 3 (emptor z zastrzeżeniami):

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

Uwaga: ten przykład może być styczny do głównej kwestii pytania i jest uwzględniony jedynie jako coś, co należy wziąć pod uwagę przy ogólnym adresowaniu brakującego StringIOmodułu. Aby uzyskać bardziej bezpośrednie rozwiązanie komunikatu TypeError: Can't convert 'bytes' object to str implicitly, zobacz tę odpowiedź .


13
Warto wspomnieć, że nie są takie same, więc możesz uzyskać TypeErrors (oczekiwany argument łańcuchowy, dostał „bajty”), jeśli dokonasz tej zmiany w izolacji. Musisz dokładnie odróżnić btyes i str (Unicode) w Pythonie 3.
Andy Hayden

7
Dla newbs takich jak ja: z importu io StringIO oznacza, że ​​wywołujesz go jako StringIO (), a nie io.StringIO ().
Noumenon,

11
Jak być właściwie kompatybilnym z Pythonem 2 i 3: po prostufrom io import StringIO
Oleh Prypin

8
TO JEST PO PROSTU ŹLE dla numpy.genfromtxt () w python 3. Proszę odnieść się do odpowiedzi Romana Shapovalova.
Bill Huang

2
@nobar: Ten ostatni. Oryginalne pytanie używa Pythona 3.x, z którego nie ma modułu StringIOi from io import BytesIOnależy go zastosować. Testowałem się na Pythonie 3.5 @ eclipse pyDev + win7 x64. Daj mi znać, jeśli się mylę, dzięki.
Bill Huang


70

W Pythonie 3 numpy.genfromtxtoczekuje strumienia bajtów. Użyj następujących opcji:

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

24

Dziękuję OP za pytanie i Roman za odpowiedź. Musiałem trochę poszukać, żeby to znaleźć; Mam nadzieję, że poniższe informacje pomagają innym.

Python 2.7

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

Na bok:

dtype = "| Sx", gdzie x = dowolny z {1, 2, 3, ...}:

dtypy. Różnica między S1 i S2 w Pythonie

„Ciągi | S1 i | S2 są deskryptorami typu danych; pierwszy oznacza, że ​​tablica przechowuje ciągi o długości 1, drugi o długości 2. ...”



17

Kod Romana Shapovalova powinien działać w Pythonie 3.x, a także w Pythonie 2.6 / 2.7. Oto znowu z pełnym przykładem:

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

Wynik:

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

Wyjaśnienie dotyczące Python 3.x:

  • numpy.genfromtxt pobiera strumień bajtów (obiekt podobny do pliku interpretowany jako bajty zamiast Unicode).
  • io.BytesIO pobiera ciąg bajtów i zwraca strumień bajtów. io.StringIO, z drugiej strony, wziąłby ciąg Unicode i zwrócił strumień Unicode.
  • x zostaje przypisany ciąg literału, który w Pythonie 3.x jest ciągiem Unicode.
  • encode()pobiera ciąg Unicode xi tworzy z niego ciąg bajtów, co daje io.BytesIOpoprawny argument.

Jedyną różnicą w Pythonie 2.6 / 2.7 jest to, że xjest to ciąg bajtów (zakładając, że from __future__ import unicode_literalsnie jest używany), a następnieencode() pobiera ciąg bajtów xi nadal tworzy z niego ten sam ciąg bajtów. Wynik jest taki sam.


Ponieważ jest to jedno z najbardziej popularnych pytań dotyczących SO StringIO, oto kilka wyjaśnień dotyczących instrukcji importu i różnych wersji Pythona.

Oto klasy, które pobierają ciąg i zwracają strumień:

  • io.BytesIO(Python 2.6, 2.7 i 3.x) - Pobiera ciąg bajtów. Zwraca strumień bajtów.
  • io.StringIO(Python 2.6, 2.7 i 3.x) - Pobiera ciąg znaków Unicode. Zwraca strumień Unicode.
  • StringIO.StringIO(Python 2.x) - Pobiera ciąg bajtów lub ciąg Unicode. Jeśli ciąg bajtów, zwraca strumień bajtów. Jeśli ciąg znaków Unicode, zwraca strumień Unicode.
  • cStringIO.StringIO(Python 2.x) - Szybsza wersja StringIO.StringIOciągów Unicode, które nie zawierają znaków ASCII, ale nie mogą z nich korzystać.

Uwaga: StringIO.StringIOjest importowany jako from StringIO import StringIO, a następnie używany jako StringIO(...). Albo to, albo zrobisz import StringIOi użyjesz StringIO.StringIO(...). Nazwa modułu i nazwa klasy są po prostu takie same. Jest podobny do datetimetego.

Czego używać, w zależności od obsługiwanych wersji Python:

  • Jeśli obsługujesz tylko Python 3.x: Po prostu użyj io.BytesIOlub w io.StringIOzależności od rodzaju danych, z którymi pracujesz.

  • Jeśli obsługujesz zarówno Python 2.6 / 2.7, jak i 3.x lub próbujesz zmienić kod z 2.6 / 2.7 na 3.x: Najłatwiejszą opcją jest nadal użycie io.BytesIOlub io.StringIO. Chociaż StringIO.StringIOjest elastyczny i dlatego wydaje się preferowany w wersji 2.6 / 2.7, ta elastyczność może maskować błędy, które pojawią się w wersji 3.x. Na przykład miałem kod, który używał StringIO.StringIOlubio.StringIO zależał od wersji Pythona, ale tak naprawdę przekazałem ciąg bajtów, więc kiedy przystąpiłem do testowania go w Pythonie 3.x, nie udało się i musiałem go naprawić.

    Kolejną zaletą korzystania io.StringIOjest obsługa uniwersalnych nowych linii. Jeśli zdasz argument słowa kluczowego newline=''w io.StringIO, to będzie w stanie podzielić linie na dowolnym \n, \r\nlub \r. Odkryłem, StringIO.StringIOże potknie się \rw szczególności.

    Zauważ, że jeśli importujesz BytesIOlub StringIOz six, dostajesz się StringIO.StringIOdo Python 2.x i odpowiedniej klasy z ioPython 3.x. Jeśli zgadzasz się z oceną z moich poprzednich akapitów, to w rzeczywistości jest to jeden przypadek, w którym powinieneś unikać sixi po prostu importować z ioniego.

  • Jeśli obsługujesz Python w wersji 2.5 lub nowszej i 3.x: Będziesz potrzebował wersji StringIO.StringIO2.5 lub nowszej, więc równie dobrze możesz użyć six. Ale zdaj sobie sprawę, że generalnie bardzo trudno jest obsługiwać zarówno wersje 2.5, jak i 3.x, więc powinieneś rozważyć obniżenie wersji najniższej obsługiwanej wersji do wersji 2.6, jeśli to w ogóle możliwe.


7

Aby przykłady z tego miejsca działały w Pythonie 3.5.2, możesz przepisać w następujący sposób:

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

Przyczyną zmiany może być to, że zawartość pliku znajduje się w danych (bajtach), które nie tworzą tekstu, dopóki nie zostaną w jakiś sposób zdekodowane. genfrombytesmoże być lepsza nazwa niż genfromtxt.


Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.