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 (caveat emptor):

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) в python 3.
Энди Хейден,

7
Для новичков, как я: из io import StringIO означает, что вы называете его как StringIO (), а не io.StringIO ().
Нумен

11
Как на самом деле быть совместимым с Python 2 и 3: простоfrom io import StringIO
Олег Припин

8
ЭТО ПРОСТО НЕПРАВИЛЬНО для numpy.genfromtxt () в python 3. Пожалуйста, обратитесь к ответу Романа Шаповалова.
Билл Хуан,

2
@nobar: последнее. Оригинальный вопрос использует Python 3.x, из которого удален модуль, StringIOи его from io import BytesIOследует применять вместо этого. Протестировал себя на python 3.5 @ eclipse pyDev + win7 x64. Пожалуйста, дайте мне знать, если я был неправ, спасибо.
Билл Хуан,



24

Спасибо ОП за ваш вопрос, а Роман за ваш ответ. Мне пришлось немного поискать, чтобы найти это; Я надеюсь, что следующее помогает другим.

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

Код Романа Шаповалова должен работать как в 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 является строкой Юникода.
  • 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.
  • 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зависимости от того, с какими данными вы работаете.

  • Если вы поддерживаете Python 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него.

  • Если вы поддерживаете Python 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=",")

Причиной изменения может быть то, что содержимое файла находится в данных (байтах), которые не создают текст, пока не будут каким-либо образом декодированы. genfrombytesможет быть лучше, чем имя genfromtxt.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.