StringIO ใน Python3


474

ฉันใช้ Python 3.2.1 และฉันไม่สามารถนำเข้าStringIOโมดูล ผมใช้ io.StringIOและการทำงาน แต่ฉันไม่สามารถใช้กับnumpy's genfromtxtเช่นนี้

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

ฉันได้รับข้อผิดพลาดต่อไปนี้:

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

และเมื่อฉันเขียนimport StringIOมันบอกว่า

ImportError: No module named 'StringIO'

คำตอบ:


774

เมื่อฉันเขียนนำเข้า StringIO มันบอกว่าไม่มีโมดูลดังกล่าว

มีอะไรใหม่ใน Python 3.0 :

StringIOและcStringIOโมดูลจะหายไป แต่นำเข้าio โมดูลและการใช้งานio.StringIOหรือio.BytesIOสำหรับข้อความและข้อมูลตามลำดับ

.


วิธีที่มีประโยชน์อาจเป็นไปได้ในการแก้ไขรหัส Python 2 เพื่อให้ทำงานใน Python 3 (ตัวสร้างคำเตือน):

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

หมายเหตุ: ตัวอย่างนี้อาจสัมผัสกับปัญหาหลักของคำถามและรวมไว้เป็นสิ่งที่ต้องพิจารณาเมื่อพูดถึงStringIOโมดูลที่หายไปโดยทั่วไป สำหรับคำตอบที่ตรงกว่านี้ให้TypeError: Can't convert 'bytes' object to str implicitlyดูที่คำตอบนี้


13
น่าจะกล่าวถึงสิ่งเหล่านี้ไม่เหมือนกันดังนั้นคุณสามารถจบลงด้วยTypeErrors (คาดว่าอาร์กิวเมนต์สตริงได้ 'ไบต์') ถ้าคุณทำการเปลี่ยนแปลงนี้ในการแยก คุณจะต้องระมัดระวังแยกแยะ btyes และ STR (Unicode) ในหลาม 3.
แอนดี้เฮย์เดน

7
สำหรับ newbs อย่างฉัน: จาก io นำเข้า StringIO หมายความว่าคุณเรียกมันว่า StringIO () ไม่ใช่ io.StringIO ()
Noumenon

11
วิธีเข้ากันได้กับ Python 2 และ 3 จริงเพียงแค่from io import StringIO
Oleh Prypin

8
นี่เป็นเรื่องง่ายสำหรับ numpy.genfromtxt () ใน python 3 โปรดอ้างอิงคำตอบจาก Roman Shapovalov
Bill Huang

2
@nobar: หลัง คำถามเดิมใช้ python 3.x ซึ่งโมดูลStringIOหายไปและfrom io import BytesIOควรใช้แทน ทดสอบด้วยตนเองใน python 3.5 @ eclipse pyDev + win7 x64 กรุณาแจ้งให้เราทราบหากฉันผิดขอบคุณ
Bill Huang


70

ใน Python 3 numpy.genfromtxtคาดว่าจะเป็นสตรีมไบต์ ใช้สิ่งต่อไปนี้:

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

24

ขอบคุณ OP สำหรับคำถามของคุณและโรมันสำหรับคำตอบของคุณ ฉันต้องค้นหาเล็กน้อยเพื่อค้นหาสิ่งนี้; ฉันหวังว่าสิ่งต่อไปนี้จะช่วยผู้อื่น

Python 2.7

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

นอกเหนือ:

dtype = "| Sx" โดยที่ x = ใด ๆ ของ {1, 2, 3, ... }:

dtypes ความแตกต่างระหว่าง S1 และ S2 ใน Python

"สตริง | S1 และ | S2 เป็นตัวบอกประเภทข้อมูลชนิดแรกหมายถึงอาร์เรย์เก็บสตริงที่มีความยาว 1, ที่สองของความยาว 2 ... "



17

รหัสของ Roman Shapovalov ควรทำงานใน Python 3.x และ Python 2.6 / 2.7 นี่คืออีกครั้งด้วยตัวอย่างที่สมบูรณ์:

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

เอาท์พุท:

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

คำอธิบายสำหรับ Python 3.x:

  • numpy.genfromtxt ใช้เวลาสตรีมไบต์ (วัตถุที่คล้ายไฟล์แปลเป็นไบต์แทน Unicode)
  • io.BytesIOใช้สตริงไบต์และส่งกลับไบต์สตรีม io.StringIOในทางกลับกันจะใช้สตริง Unicode และส่งคืนสตรีม Unicode
  • x ได้รับการกำหนดสตริงตัวอักษรซึ่งใน Python 3.x เป็นสตริง Unicode
  • encode()ใช้สตริง Unicode xและสร้างสตริงไบต์จากนั้นจึงให้io.BytesIOอาร์กิวเมนต์ที่ถูกต้อง

ความแตกต่างเพียงอย่างเดียวสำหรับ Python 2.6 / 2.7 คือxสตริงไบต์ (สมมติfrom __future__ import unicode_literalsว่าไม่ได้ใช้) จากนั้นencode()ใช้สตริงไบต์xและยังคงทำให้สตริงไบต์เดียวกันหลุดออกมา ดังนั้นผลลัพธ์เหมือนกัน


เนื่องจากนี่เป็นหนึ่งในคำถามยอดนิยมของ SO ต่อไปนี้เป็นStringIOคำอธิบายเพิ่มเติมเกี่ยวกับข้อความสั่งการนำเข้าและเวอร์ชัน Python ที่แตกต่าง

นี่คือคลาสที่รับสตริงและส่งคืนสตรีม:

  • io.BytesIO(Python 2.6, 2.7 และ 3.x) - ใช้สตริงไบต์ ส่งคืนกระแสข้อมูลไบต์
  • io.StringIO(Python 2.6, 2.7 และ 3.x) - ใช้สตริง Unicode ส่งคืนกระแส Unicode
  • StringIO.StringIO(Python 2.x) - ใช้สตริงไบต์หรือสตริง Unicode ถ้าสตริงไบต์ส่งคืนกระแสไบต์ หากสตริง Unicode ส่งคืนสตรีม Unicode
  • cStringIO.StringIO(Python 2.x) - เวอร์ชันที่เร็วกว่าStringIO.StringIOแต่ไม่สามารถใช้สตริง Unicode ซึ่งมีอักขระที่ไม่ใช่ ASCII

ทราบว่าStringIO.StringIOจะนำเข้าเป็นใช้เป็นแล้วfrom StringIO import StringIO StringIO(...)ทั้งที่หรือที่คุณทำและการใช้งานแล้วimport StringIO StringIO.StringIO(...)ชื่อโมดูลและชื่อคลาสเพิ่งจะเหมือนกัน มันคล้ายกับdatetimeวิธีนั้น

สิ่งที่จะใช้ขึ้นอยู่กับเวอร์ชัน Python ที่คุณรองรับ:

  • หากคุณสนับสนุน Python 3.x:เพียงแค่ใช้io.BytesIOหรือio.StringIOขึ้นอยู่กับประเภทของข้อมูลที่คุณใช้งาน

  • หากคุณสนับสนุนทั้งงูหลาม 2.6 / 2.7 และ 3.x หรือกำลังพยายามที่จะเปลี่ยนรหัสของคุณจาก 2.6 / 2.7 3.x:ตัวเลือกที่ง่ายที่สุดคือยังคงใช้งานหรือio.BytesIO io.StringIOแม้ว่าStringIO.StringIOจะมีความยืดหยุ่นและดูเหมือนว่าเหมาะสำหรับ 2.6 / 2.7 แต่ความยืดหยุ่นนั้นสามารถปกปิดข้อบกพร่องที่จะปรากฏใน 3.x ตัวอย่างเช่นฉันมีรหัสที่ใช้StringIO.StringIOหรือio.StringIOขึ้นอยู่กับรุ่น Python แต่ฉันผ่านไบต์สตริงจริงดังนั้นเมื่อฉันได้รอบเพื่อทดสอบใน Python 3.x มันล้มเหลวและต้องแก้ไข

    ข้อดีอีกอย่างของการใช้io.StringIOคือการสนับสนุนบรรทัดใหม่สากล ถ้าคุณผ่านอาร์กิวเมนต์คำหลักที่newline=''เข้าไปio.StringIOก็จะสามารถที่จะแบ่งสายใด ๆ\n, หรือ\r\n \rฉันพบว่าStringIO.StringIOจะเดินทาง\rโดยเฉพาะอย่างยิ่ง

    โปรดทราบว่าถ้าคุณนำเข้าBytesIOหรือStringIOจากsixคุณจะได้รับStringIO.StringIOใน Python 2.x และคลาสที่เหมาะสมจากioใน Python 3.x หากคุณเห็นด้วยกับการประเมินย่อหน้าก่อนหน้าของฉันนี่เป็นกรณีหนึ่งที่คุณควรหลีกเลี่ยงsixและเพียงนำเข้าจากioแทน

  • หากคุณสนับสนุนหลาม 2.5 หรือลดและ 3.x:คุณจะต้องStringIO.StringIO2.5 sixหรือต่ำกว่าดังนั้นคุณอาจรวมทั้งการใช้งาน แต่จงตระหนักว่าโดยทั่วไปแล้วมันยากมากที่จะรองรับทั้ง 2.5 และ 3.x ดังนั้นคุณควรพิจารณากระแทกเวอร์ชันที่ต่ำที่สุดที่สนับสนุนเป็น 2.6 ถ้าทำได้


7

เพื่อให้ตัวอย่างจากที่นี่ ทำงานร่วมกับ Python 3.5.2 คุณสามารถเขียนใหม่ได้ดังนี้:

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

เหตุผลของการเปลี่ยนแปลงอาจเป็นเพราะเนื้อหาของไฟล์อยู่ในข้อมูล (ไบต์) ซึ่งไม่ได้สร้างข้อความจนกว่าจะถูกถอดรหัสอย่างใด อาจจะเป็นชื่อที่ดีกว่าgenfrombytesgenfromtxt


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.