Для чого використовується StringIO в python насправді?


75

Я не професіонал, і я чухаю голову, розуміючи, для чого саме використовується StringIO. Я шукав деякі приклади в Інтернеті. Однак майже всі приклади дуже абстрактні. І вони просто показують "як" ним користуватися. Але жоден з них не показує "чому" та "за яких обставин" це слід / буде використовувати? Спасибі заздалегідь

ps не слід плутати з цим питанням щодо stackoverflow : StringIO Usage, яке порівнює рядок та StringIo.

Відповіді:


90

Він використовується, коли у вас є якийсь API, який приймає лише файли, але вам потрібно використовувати рядок. Наприклад, для стиснення рядка за допомогою модуля gzip у Python 2:

import gzip
import StringIO

stringio = StringIO.StringIO()
gzip_file = gzip.GzipFile(fileobj=stringio, mode='w')
gzip_file.write('Hello World')
gzip_file.close()

stringio.getvalue()

2
іншими словами:: duck typingD
Абделуахаб

2
Починаючи з Python 3.2, модуль gzip має функції безпосереднього стиснення даних. (Але будь-яка відома бібліотека з відкритим кодом, яка в даний час потребує StringIO, можливо, через деякий час буде розвивати такі функції, тому замість пошуку нового прикладу я залишу тут gzip.)
Петро Вікторін,

36

StringIO надає файлоподібний доступ до рядків, тому ви можете використовувати існуючий модуль, який має справу з файлом і майже нічого не змінювати і змусити його працювати з рядками.

Наприклад, скажімо, у вас є реєстратор, який записує речі у файл, і ви хочете замість цього надіслати вихідні дані журналу через мережу. Ви можете прочитати файл і записати його вміст в мережу, або ви можете записати журнал в об'єкт StringIO і відправити його до місця призначення, не торкаючись файлової системи. StringIO дозволяє легко зробити це першим способом, а потім перейти на другий спосіб.


1
stringIO також корисний при написанні файлу безпосередньо в S3 (тобто без необхідності зберігати локально, а потім завантажувати).
7bСтан

17

У випадках, коли ви хочете схожий на файл об’єкт, який ДІЄ як файл, але пише в буфер рядків в пам’яті: інструментом є StringIO. Якщо ви створюєте великі рядки, наприклад, текстові документи, і робите багато конкатенації рядків, вам може бути простіше просто використовувати StringIO замість групи mystr += 'more stuff\n'операцій.


3
Я також виявив, StringIOщо значно швидше, якщо ви маєте справу з кількома мегабайтами символьних даних у порівнянні з виразами, як mystr += "more stuff\n"у циклі, особливо якщо ви можете використовувати cStringIO.StringIOзамість просто io.StringIO.
Рідко `` Де Моніка '' потрібна

@SeldomNeedy Ви його порівняли? Це могло бути правдою в 2016 році, але об’єднання рядків з + = досить оптимізовано в наші дні (він використовує лічильник посилань для мутації рядка на місці, коли це безпечно зробити). Орієнтир: $ python3 -m timeit -s "from io import StringIO; line = 'a'*80" $'s = StringIO()\nfor i in range(10000): s.write(line)\ns = s.getvalue()'500 loops, best of 5: 599 usec per loop; python3 -m timeit -s "line = 'a'*80" $'s = ""\nfor i in range(10000): s += line'500 loops, best of 5: 588 usec per loop
Клеман

@ Clément Я мав на увазі Python 2.x; cStringIOнавіть не існує в Python 3. Приємно бачити, як наївна реалізація добре оптимізована в 3.x!
Рідко "Де Моніка" Потребність

@SeldomNeedy +=був добре оптимізований і в Python 2, AFAICT: +=версія базового тесту в десять разів швидша, ніж StringIO, і в 3 рази швидше, ніж StringIO в Python2. (Крім того, у вашому дописі згадується io.StringIO; хіба це не лише Python 3?)
Клемен


10

Кілька речей, для яких я особисто використовував:

  1. Кешування цілих файлів. У мене є сценарій, який читає PDF-файли та перевіряє різні речі про них. Бібліотека PDF, яку я використовую, бере конструктор відкритих файлів у своєму конструкторі документів. Спочатку я просто відкрив PDF-файл, який мені було цікаво прочитати, однак, коли я змінив його, щоб відразу прочитати весь файл у пам’яті, а потім передав об’єкт StringIO в бібліотеку PDF, час роботи мого сценарію скоротився вдвічі.

  2. Відкладений друк. Той же сценарій друкує заголовок перед кожним PDF-файлом, який він читає. Однак я можу вказати в командному рядку, чи ігнорувати певні тести, що містяться у його файлі конфігурації, чи включати лише певні. Якщо я проігнорую всі тести для певного PDF, я не хочу надрукувати заголовок, але я не буду знати, скільки тестів я провів, поки не закінчу тестувати (тести також можна визначити динамічно). Тому я захоплюю заголовок в об’єкт StringIO, змінюючи sys.stdoutвказівник на нього, і кожного разу, коли я запускаю тест, я перевіряю, чи є в цьому об’єкті щось. Якщо так, я друкую його і скидаю до порожнього. Вуаля, лише PDF-файли, що мають тести, надрукують заголовки.


9

Я щойно використовував StringIO на практиці для двох речей:

  • Провести модульне тестування скрипта, який багато в чому впливає print, перенаправляючи sys.stdoutна StringIOекземпляр для зручного аналізу;
  • Створити гарантовано сформований XML-документ (користувацький запит API) за допомогою, ElementTreeа потім writeйого для надсилання через з'єднання HTTP.

Не те, що вам потрібно StringIO часто , але іноді це досить корисно.


7

Я використовував його замість текстових файлів для модульного тестування.

Наприклад, щоб створити файл CSV для тестування з пандами (Python 3):

import io
f = io.StringIO("id,name\n1,brian\n2,amanda\n3,zoey\n")
df = pd.read_csv(f) # pandas takes a file path or a file-like object

З документації тут :

Потік пам’яті для вводу-виводу тексту. Текстовий буфер відкидається, коли викликається метод close ().

Початкове значення буфера можна встановити, вказавши початкове_значення.

метод getvalue (): Повертає str, що містить весь вміст буфера.


1

Django має функцію, call_commandяка використовується для виклику команд управління. Ця функція друкує вихідні дані в stdout і не повертає жодного значення. Якщо ви хочете знати, чи команда успішно виконана чи ні, вам слід переглянути вихідні дані та вирішити.

Використовуючи StringIO, ви можете зафіксувати вихідні дані та перевірити, чи бажаний вивід чи ні.

with io.StringIO() as output:
    call_command('custom_command', stdout=output)
    if 'Success' not in output.getvalue():
        print('Custom command failed...')

0

Ось конкретний приклад використання StringIO: запис деяких даних безпосередньо в aws s3 без необхідності створювати файл на локальному диску:

import csv
import io
import boto3

data = [
    ["test", "data", "headers etc", "123","",],
    ["blah", "123", "35", "blah","",],
    ["abc", "def", "blah", "yep", "blah"]
]

bucket_name = 'bucket_name_here'
session = boto3.Session(
    aws_access_key_id = "fake Access ID"),
    aws_secret_access_key = "fake Secret key"),
    region_name = "ap-southeast-2")
)
s3 = session.resource('s3')
with io.StringIO() as f:
    writer = csv.writer(f, delimiter=",")
    writer.writerows(data)
    resp = s3.Object(bucket_name, "test.csv").put(Body=f.getvalue())

Насолоджуйтесь новим CSV на S3, не записуючи нічого на локальний диск!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.