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'

Відповіді:


773

коли я пишу імпорт 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) у python 3.
Енді Хейден,

7
Для новичок, як я: з імпорту io 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, ...}:

типи. Різниця між 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 є рядком 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залежно від типу даних, з яким ви працюєте.

  • Якщо ви підтримуєте і 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 та відповідний клас з ioPython 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.