StringIO dalam Python3


474

Saya menggunakan Python 3.2.1 dan saya tidak bisa mengimpor StringIOmodul. Saya menggunakan io.StringIOdan bekerja, tapi aku tidak bisa menggunakannya dengan numpy's genfromtxtseperti ini:

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

Saya mendapatkan kesalahan berikut:

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

dan ketika saya menulis import StringIOitu mengatakan

ImportError: No module named 'StringIO'

Jawaban:


774

ketika saya menulis impor StringIO dikatakan tidak ada modul seperti itu.

Dari What's New In Python 3.0 :

The StringIOdan cStringIOmodul pergi. Sebaliknya, impor io modul dan penggunaan io.StringIOatau io.BytesIOuntuk teks dan data masing-masing.

.


Metode yang mungkin berguna untuk memperbaiki beberapa kode Python 2 juga berfungsi di Python 3 (peringatan sebelumnya):

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

Catatan: Contoh ini mungkin bersinggungan dengan masalah utama dari pertanyaan dan dimasukkan hanya sebagai sesuatu untuk dipertimbangkan ketika secara umum menangani StringIOmodul yang hilang . Untuk solusi pesan yang lebih langsung TypeError: Can't convert 'bytes' object to str implicitly, lihat jawaban ini .


13
Layak disebutkan ini tidak sama, sehingga Anda bisa berakhir dengan TypeErrors (argumen string diharapkan, mendapat 'byte') jika Anda membuat perubahan ini secara terpisah. Anda perlu membedakan btyes dan str (unicode) dengan hati-hati dengan python 3.
Andy Hayden

7
Untuk pemula seperti saya: dari io import StringIO berarti Anda menyebutnya sebagai StringIO (), bukan io.StringIO ().
Noumenon

11
Bagaimana sebenarnya bisa kompatibel dengan Python 2 dan 3: justfrom io import StringIO
Oleh Prypin

8
INI HANYA SALAH untuk numpy.genfromtxt () dalam python 3. Silakan merujuk ke jawaban dari Roman Shapovalov.
Bill Huang

2
@ nobar: Yang terakhir. Pertanyaan aslinya menggunakan python 3.x, dari mana modul StringIOhilang dan from io import BytesIOharus diterapkan sebagai gantinya. Menguji diri saya pada python 3.5 @ eclipse pyDev + win7 x64. Tolong beri tahu saya kalau saya salah, terima kasih.
Bill Huang


70

Pada Python 3 numpy.genfromtxtmengharapkan aliran byte. Gunakan yang berikut ini:

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

24

Terima kasih OP atas pertanyaan Anda, dan Roman atas jawaban Anda. Saya harus mencari sedikit untuk menemukan ini; Saya harap yang berikut ini membantu orang lain.

Python 2.7

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

Ke samping:

dtype = "| Sx", di mana x = sembarang dari {1, 2, 3, ...}:

tipe. Perbedaan antara S1 dan S2 dalam Python

"String | S1 dan | S2 adalah deskriptor tipe data; yang pertama berarti array memiliki string dengan panjang 1, yang kedua dari panjang 2. ..."



17

Kode Roman Shapovalov harus bekerja dalam Python 3.x dan juga Python 2.6 / 2.7. Ini dia lagi dengan contoh lengkap:

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

Keluaran:

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

Penjelasan untuk Python 3.x:

  • numpy.genfromtxt mengambil aliran byte (objek seperti file yang ditafsirkan sebagai byte alih-alih Unicode).
  • io.BytesIOmengambil string byte dan mengembalikan aliran byte. io.StringIO, di sisi lain, akan mengambil string Unicode dan dan mengembalikan aliran Unicode.
  • x akan diberi string literal, yang dalam Python 3.x adalah string Unicode.
  • encode()mengambil string Unicode xdan membuat byte string darinya, sehingga memberikan io.BytesIOargumen yang valid.

Satu-satunya perbedaan untuk Python 2.6 / 2.7 adalah xstring byte (dengan asumsi from __future__ import unicode_literalstidak digunakan), dan kemudian encode()mengambil string byte xdan masih membuat string byte yang sama darinya. Jadi hasilnya sama.


Karena ini adalah salah satu pertanyaan SO yang paling populer StringIO, inilah beberapa penjelasan lebih lanjut tentang pernyataan impor dan versi Python yang berbeda.

Berikut adalah kelas-kelas yang mengambil string dan mengembalikan aliran:

  • io.BytesIO(Python 2.6, 2.7, dan 3.x) - Mengambil string byte. Mengembalikan aliran byte.
  • io.StringIO(Python 2.6, 2.7, dan 3.x) - Mengambil string Unicode. Mengembalikan aliran Unicode.
  • StringIO.StringIO(Python 2.x) - Mengambil string byte atau string Unicode. Jika byte string, mengembalikan aliran byte. Jika string Unicode, mengembalikan aliran Unicode.
  • cStringIO.StringIO(Python 2.x) - Versi lebih cepat dari StringIO.StringIO, tetapi tidak dapat mengambil string Unicode yang berisi karakter non-ASCII.

Catatan yang StringIO.StringIOdiimpor sebagai from StringIO import StringIO, lalu digunakan sebagai StringIO(...). Entah itu, atau Anda lakukan import StringIOdan kemudian gunakan StringIO.StringIO(...). Nama modul dan nama kelas kebetulan sama. Mirip seperti datetimeitu.

Apa yang harus digunakan, tergantung pada versi Python yang didukung:

  • Jika Anda hanya mendukung Python 3.x: Cukup gunakan io.BytesIOatau io.StringIOtergantung pada jenis data yang Anda gunakan .

  • Jika Anda mendukung Python 2.6 / 2.7 dan 3.x, atau mencoba mentransisikan kode Anda dari 2.6 / 2.7 ke 3.x: Opsi termudah adalah masih menggunakan io.BytesIOatau io.StringIO. Meskipun StringIO.StringIOfleksibel dan dengan demikian tampaknya lebih disukai untuk 2.6 / 2.7, fleksibilitas itu dapat menutupi bug yang akan bermanifestasi dalam 3.x. Sebagai contoh, saya punya beberapa kode yang digunakan StringIO.StringIOatau io.StringIOtergantung pada versi Python, tapi saya benar-benar melewati string byte, jadi ketika saya sempat mengujinya di Python 3.x gagal dan harus diperbaiki.

    Keuntungan lain menggunakan io.StringIOadalah dukungan untuk baris baru universal. Jika Anda melewatkan argumen kata kunci newline=''ke dalam io.StringIO, itu akan dapat membagi baris pada salah \n, \r\natau \r. Saya menemukan bahwa StringIO.StringIOakan naik pada \rkhususnya.

    Perhatikan bahwa jika Anda mengimpor BytesIOatau StringIOdari six, Anda mendapatkan StringIO.StringIOPython 2.x dan kelas yang sesuai dari iodalam Python 3.x. Jika Anda setuju dengan penilaian paragraf saya sebelumnya, ini sebenarnya adalah satu kasus di mana Anda harus menghindari sixdan hanya mengimpor dari io.

  • Jika Anda mendukung Python 2.5 atau lebih rendah dan 3.x: Anda perlu StringIO.StringIOuntuk 2.5 atau lebih rendah, jadi sebaiknya Anda gunakan six. Tetapi sadari bahwa umumnya sangat sulit untuk mendukung 2.5 dan 3.x, jadi Anda harus mempertimbangkan untuk menabrak versi terendah yang didukung ke 2.6 jika memungkinkan.


7

Untuk membuat contoh dari sini berfungsi dengan Python 3.5.2, Anda dapat menulis ulang sebagai berikut:

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

Alasan untuk perubahan mungkin karena konten file dalam data (byte) yang tidak membuat teks sampai diterjemahkan entah bagaimana. genfrombytesmungkin nama yang lebih baik daripada genfromtxt.


Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.