StringIO в Python3
Я использую Python 3.2.1 и не могу импортировать модуль StringIO
. Я использую io.StringIO
и он работает, но я не могу использовать его с numpy
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'
Ответы
Ответ 1
когда я пишу import 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
см. этот ответ.
Ответ 2
В моем случае я использовал:
from io import StringIO
Ответ 3
В Python 3 numpy.genfromtxt
ожидает поток байтов. Используйте следующее:
numpy.genfromtxt(io.BytesIO(x.encode()))
Ответ 4
Спасибо ОП за ваш вопрос, а Роман за ваш ответ. Мне пришлось немного поискать, чтобы найти это; Я надеюсь, что следующее поможет другим.
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...."
Ответ 5
С помощью six:
import six
import numpy
x = "1 3\n 4.5 8"
numpy.genfromtxt(six.StringIO(x))
Ответ 6
Код Романа Шаповалова должен работать как в 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
и по-прежнему создает из нее ту же байтовую строку. Так что результат тот же.
Поскольку это один из самых популярных вопросов, касающихся 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.StringIO
для 2.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
.
Ответ 8
попробуйте это
из StringIO import StringIO
x = "1 3\n 4,5 8"
numpy.genfromtxt(StringIO (х))