StringIO trong Python3


474

Tôi đang sử dụng Python 3.2.1 và tôi không thể nhập StringIOmô-đun. Tôi sử dụng io.StringIOvà nó hoạt động, nhưng tôi không thể sử dụng nó với numpy's genfromtxtnhư thế này:

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

Tôi nhận được lỗi sau đây:

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

và khi tôi viết import StringIOnó nói

ImportError: No module named 'StringIO'

Câu trả lời:


774

Khi tôi viết nhập StringIO, nó báo không có mô-đun như vậy.

Từ những gì mới trong Python 3.0 :

Các StringIOcStringIOmô-đun biến mất. Thay vào đó, nhập io mô-đun và sử dụng io.StringIOhoặc io.BytesIOcho văn bản và dữ liệu tương ứng.

.


Một phương pháp có thể hữu ích để sửa một số mã Python 2 cũng hoạt động trong Python 3 (caveat emptor):

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

Lưu ý: Ví dụ này có thể tiếp tuyến với vấn đề chính của câu hỏi và chỉ được đưa vào như một điều cần xem xét khi giải quyết chung về StringIOmô-đun bị thiếu . Đối với một giải pháp trực tiếp hơn thông điệp TypeError: Can't convert 'bytes' object to str implicitly, xem câu trả lời này .


13
Đáng nói là những cái này không giống nhau, vì vậy bạn có thể kết thúc bằng TypeErrors (đối số chuỗi dự kiến, có 'byte') nếu bạn thực hiện thay đổi này một cách cô lập. Bạn cần phân biệt cẩn thận btyes và str (unicode) trong python 3.
Andy Hayden

7
Đối với những người mới như tôi: từ io nhập StringIO có nghĩa là bạn gọi nó là StringIO (), không phải io.StringIO ().
Noumenon 7/07/2015

11
Cách thực sự tương thích với Python 2 và 3: chỉfrom io import StringIO
Oleh Prypin

8
ĐÂY LÀ ĐƠN GIẢN SAU cho numpy.genfromtxt () trong python 3. Vui lòng tham khảo câu trả lời từ Roman Shapovalov.
Bill Huang

2
@nobar: Cái sau. Câu hỏi ban đầu sử dụng python 3.x, từ đó mô-đun StringIObiến mất và from io import BytesIOnên được áp dụng thay thế. Đã thử nghiệm bản thân trên python 3.5 @ nhật thực pyDev + win7 x64. Xin vui lòng cho tôi biết nếu tôi sai cảm ơn.
Bill Huang

131

Trong trường hợp của tôi, tôi đã sử dụng:

from io import StringIO

70

Trên Python 3 numpy.genfromtxtmong đợi một luồng byte. Sử dụng như sau:

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

24

Cảm ơn OP vì câu hỏi của bạn và Roman cho câu trả lời của bạn. Tôi đã phải tìm kiếm một chút để tìm thấy điều này; Tôi hy vọng sau đây giúp đỡ người khác.

Python 2.7

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

Con trăn 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.]]
"""

Qua một bên:

dtype = "| Sx", trong đó x = bất kỳ {1, 2, 3, ...}:

dtypes. Sự khác biệt giữa S1 và S2 trong Python

"Các chuỗi | S1 và | S2 là các mô tả kiểu dữ liệu; đầu tiên có nghĩa là mảng giữ các chuỗi có độ dài 1, thứ hai có độ dài 2. ..."



17

Mã của Roman Shapovalov sẽ hoạt động trong Python 3.x cũng như Python 2.6 / 2.7. Đây là một lần nữa với ví dụ đầy đủ:

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

Đầu ra:

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

Giải thích cho Python 3.x:

  • numpy.genfromtxt lấy một luồng byte (một đối tượng giống như tệp được hiểu là byte thay vì Unicode).
  • io.BytesIOlấy một chuỗi byte và trả về một luồng byte. io.StringIOmặt khác, sẽ lấy một chuỗi Unicode và trả về một luồng Unicode.
  • x được gán một chuỗi ký tự, trong Python 3.x là một chuỗi Unicode.
  • encode()lấy chuỗi Unicode xvà tạo ra một chuỗi byte từ nó, do đó đưa ra io.BytesIOmột đối số hợp lệ.

Sự khác biệt duy nhất cho Python 2.6 / 2.7 là xmột chuỗi byte (giả sử from __future__ import unicode_literalskhông được sử dụng), sau đó encode()lấy chuỗi byte xvà vẫn tạo ra chuỗi byte tương tự từ nó. Vì vậy, kết quả là như nhau.


Vì đây là một trong những câu hỏi phổ biến nhất của SO liên quan đến StringIO , nên đây là một số giải thích thêm về báo cáo nhập khẩu và các phiên bản Python khác nhau.

Dưới đây là các lớp lấy một chuỗi và trả về một luồng:

  • io.BytesIO(Python 2.6, 2.7 và 3.x) - Lấy chuỗi byte. Trả về một luồng byte.
  • io.StringIO(Python 2.6, 2.7 và 3.x) - Tạo chuỗi Unicode. Trả về luồng Unicode.
  • StringIO.StringIO(Python 2.x) - Lấy chuỗi byte hoặc chuỗi Unicode. Nếu chuỗi byte, trả về một luồng byte. Nếu chuỗi Unicode, trả về luồng Unicode.
  • cStringIO.StringIO(Python 2.x) - Phiên bản nhanh hơn StringIO.StringIO, nhưng không thể lấy các chuỗi Unicode có chứa các ký tự không phải ASCII.

Lưu ý rằng StringIO.StringIOđược nhập dưới dạng from StringIO import StringIO, sau đó được sử dụng như StringIO(...). Hoặc là, hoặc bạn làm import StringIOvà sau đó sử dụng StringIO.StringIO(...). Tên mô-đun và tên lớp chỉ xảy ra giống nhau. Nó tương tự như datetimevậy.

Sử dụng cái gì, tùy thuộc vào các phiên bản Python được hỗ trợ của bạn:

  • Nếu bạn chỉ hỗ trợ Python 3.x: Chỉ cần sử dụng io.BytesIOhoặc io.StringIOtùy thuộc vào loại dữ liệu bạn đang làm việc.

  • Nếu bạn hỗ trợ cả Python 2.6 / 2.7 và 3.x hoặc đang cố chuyển đổi mã của bạn từ 2.6 / 2.7 sang 3.x: Tùy chọn đơn giản nhất vẫn là sử dụng io.BytesIOhoặc io.StringIO. Mặc dù StringIO.StringIOlà linh hoạt và do đó dường như được ưa thích cho 2.6 / 2.7, tính linh hoạt đó có thể che giấu các lỗi sẽ xuất hiện trong 3.x. Ví dụ, tôi có một số mã được sử dụng StringIO.StringIOhoặcio.StringIO tùy thuộc vào phiên bản Python, nhưng tôi thực sự đã truyền một chuỗi byte, vì vậy khi tôi đi kiểm tra nó trong Python 3.x thì nó đã bị lỗi và phải sửa.

    Một lợi thế khác của việc sử dụng io.StringIOlà hỗ trợ cho các dòng mới phổ quát. Nếu bạn vượt qua đối số từ khóa newline=''vào io.StringIO, nó sẽ có thể chia dòng trên bất kỳ \n, \r\nhoặc \r. Tôi thấy rằng StringIO.StringIOsẽ đi lên trên\r đặc biệt.

    Lưu ý rằng nếu bạn nhập BytesIOhoặc StringIOtừ six, bạn nhận được StringIO.StringIOtrong Python 2.x và lớp thích hợp từ iotrong Python 3.x. Nếu bạn đồng ý với đánh giá của các đoạn trước của tôi, đây thực sự là một trường hợp bạn nên tránh sixvà chỉ nhập từ iothay thế.

  • Nếu bạn hỗ trợ Python 2.5 trở xuống và 3.x: Bạn sẽ cần StringIO.StringIO2.5 hoặc thấp hơn, vì vậy bạn cũng có thể sử dụng six. Nhưng nhận ra rằng nhìn chung rất khó để hỗ trợ cả 2.5 và 3.x, vì vậy bạn nên cân nhắc giảm phiên bản được hỗ trợ thấp nhất của mình xuống 2.6 nếu có thể.


7

Để làm cho các ví dụ từ đây hoạt động với Python 3.5.2, bạn có thể viết lại như sau:

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

Lý do cho sự thay đổi có thể là nội dung của tệp nằm trong dữ liệu (byte) không tạo ra văn bản cho đến khi được giải mã bằng cách nào đó. genfrombytescó thể là một tên tốt hơn genfromtxt.


Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.