Spec-Zone.ru › Python 3.9

Ввод и вывод

Существует несколько способов представить вывод программы; данные могут быть напечатаны в удобочитаемой форме или записаны в файл для дальнейшего использования. В этой главе будут рассмотрены некоторые возможности.

7.1. Форматирование вывода

До сих пор мы сталкивались с двумя способами записи значений: выражениями-утверждениями и функцией print(). (Третий способ — использование метода write() объектов файлов; стандартный вывод файла может быть сохранён как sys.stdout. Дополнительную информацию по этому вопросу см. в Справочнике по библиотеке.)

Часто вам потребуется больший контроль над форматированием вывода, чем просто печать значений, разделённых пробелами. Существует несколько способов форматирования вывода.

  • Чтобы использовать форматируемые строковые литералы, начните строку с f или F перед открывающей кавычкой или тройной кавычкой. Внутри этой строки вы можете записать выражение Python между символами { и }, которое может ссылаться на переменные или литеральные значения.

    >>> year = 2016
    >>> event = 'Referendum'
    >>> f'Results of the {year} {event}'
    'Results of the 2016 Referendum'
    
  • Метод str.format() строк требует больше ручного вмешательства. Вы по-прежнему будете использовать { и } для обозначения места, куда будет подставлена переменная, и сможете предоставить подробные директивы форматирования, но также вам потребуется предоставить информацию для форматирования.

    >>> yes_votes = 42_572_654
    >>> no_votes = 43_132_495
    >>> percentage = yes_votes / (yes_votes + no_votes)
    >>> '{:-9} YES votes  {:2.2%}'.format(yes_votes, percentage)
    ' 42572654 YES votes  49.67%'
    
  • Наконец, вы можете выполнить все операции обработки строк самостоятельно, используя операции срезов и конкатенации строк, чтобы создать любой необходимый макет. Тип строки имеет некоторые методы, которые выполняют полезные операции для выравнивания строк по заданной ширине столбца.

Когда вам не нужен сложный вывод, а нужно просто быстро отобразить некоторые переменные для отладки, вы можете преобразовать любое значение в строку с помощью функций repr() или str().

Функция str() предназначена для возврата представлений значений, которые достаточно удобочитаемы для человека, тогда как repr() предназначена для генерации представлений, которые могут быть прочитаны интерпретатором (или приведут к ошибке SyntaxError, если эквивалентного синтаксиса нет). Для объектов, у которых нет особого представления для человека, str() вернёт то же значение, что и repr(). У многих значений, таких как числа или структуры, подобные спискам и словарям, представление одинаковое с использованием любой из функций. У строк, в частности, есть два разных представления.

Примеры:

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1/7)
'0.14285714285714285'
>>> x = 10 * 3.25
>>> y = 200 * 200
>>> s = 'The value of x is ' + repr(x) + ', and y is ' + repr(y) + '...'
>>> print(s)
The value of x is 32.5, and y is 40000...
>>> # The repr() of a string adds string quotes and backslashes:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # The argument to repr() may be any Python object:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"

Модуль string содержит класс Template, который предлагает ещё один способ подстановки значений в строки, используя плейсхолдеры, подобные $x, и заменяя их значениями из словаря, но он предлагает гораздо меньше контроля над форматированием.

7.1.1. Форматируемые строковые литералы

Форматируемые строковые литералы (также называемые f-строками) позволяют включать значение выражений Python в строку, добавляя префикс f или F к строке и записывая выражения как {expression}.

После выражения может следовать необязательный спецификатор формата. Это позволяет лучше контролировать форматирование значения. В следующем примере число пи округляется до трёх знаков после запятой:

>>> import math
>>> print(f'The value of pi is approximately {math.pi:.3f}.')
The value of pi is approximately 3.142.

Передача целого числа после ':' приведет к тому, что это поле будет иметь минимальную ширину в заданном количестве символов. Это полезно для выравнивания столбцов.

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print(f'{name:10} ==> {phone:10d}')
...
Sjoerd     ==>       4127
Jack       ==>       4098
Dcab       ==>       7678

Другие модификаторы могут быть использованы для преобразования значения перед его форматированием. '!a' применяет ascii(), '!s' применяет str(), а '!r' применяет repr():

>>> animals = 'eels'
>>> print(f'My hovercraft is full of {animals}.')
My hovercraft is full of eels.
>>> print(f'My hovercraft is full of {animals!r}.')
My hovercraft is full of 'eels'.

Для справки по этим спецификациям форматирования см. справочное руководство для Мини-язык спецификаций форматирования.

7.1.2. Метод format() строки

Основное использование метода str.format() выглядит так:

>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"

Скобки и символы внутри них (называемые полями форматирования) заменяются объектами, переданными в метод str.format(). Номер в скобках может использоваться для ссылки на позицию объекта, переданного в метод str.format().

>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam

Если в методе str.format() используются ключевые аргументы, их значения ссылаются с помощью имени аргумента.

>>> print('This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.

Позиционные и ключевые аргументы могут быть произвольным образом объединены:

>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                       other='Georg'))
The story of Bill, Manfred, and Georg.

Если у вас очень длинная строка форматирования, которую вы не хотите разбивать, было бы неплохо, если бы вы могли ссылаться на переменные, которые нужно отформатировать, по имени, а не по позиции. Это можно сделать, просто передав словарь и используя квадратные скобки '[]' для доступа к ключам.

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {0[Jack]:d}; Sjoerd: {0[Sjoerd]:d}; '
...       'Dcab: {0[Dcab]:d}'.format(table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Это также можно сделать, передав таблицу в качестве ключевых аргументов с помощью обозначения «**».

>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 8637678}
>>> print('Jack: {Jack:d}; Sjoerd: {Sjoerd:d}; Dcab: {Dcab:d}'.format(**table))
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Это особенно полезно в сочетании со встроенной функцией vars(), которая возвращает словарь, содержащий все локальные переменные.

В качестве примера, следующие строки создают аккуратно выровненную таблицу, содержащую целые числа и их квадраты и кубы:

>>> for x in range(1, 11):
...     print('{0:2d} {1:3d} {2:4d}'.format(x, x*x, x*x*x))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

Полное описание форматирования строк с помощью str.format() см. в разделе Синтаксис форматирования строк.

7.1.3. Ручное форматирование строк

Вот та же таблица квадратов и кубов, отформатированная вручную:

>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # Note use of 'end' on previous line
...     print(repr(x*x*x).rjust(4))
...
 1   1    1
 2   4    8
 3   9   27
 4  16   64
 5  25  125
 6  36  216
 7  49  343
 8  64  512
 9  81  729
10 100 1000

(Обратите внимание, что один пробел между каждым столбцом был добавлен способом работы print(): он всегда добавляет пробелы между своими аргументами.)

Метод str.rjust() объектов строк выравнивает строку по правому краю в поле заданной ширины, дополняя её пробелами слева. Существуют аналогичные методы str.ljust() и str.center(). Эти методы не записывают ничего, они просто возвращают новую строку. Если входная строка слишком длинная, они её не усекают, а возвращают без изменений; это может нарушить ваш макет столбцов, но это обычно лучше, чем альтернатива, которая бы давала ложную информацию о значении. (Если вам действительно нужно усечение, вы всегда можете добавить операцию среза, как в x.ljust(n)[:n].)

Есть ещё один метод, str.zfill(), который дополняет числовую строку слева нулями. Он понимает знаки плюс и минус:

>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'

7.1.4. Старое форматирование строк

Оператор % (модуль) также может использоваться для форматирования строк. Учитывая 'string' % values, экземпляры % в string заменяются нулём или более элементами values. Эта операция обычно известна как интерполяция строк. Например:

>>> import math
>>> print('The value of pi is approximately %5.3f.' % math.pi)
The value of pi is approximately 3.142.

Более подробную информацию можно найти в разделе Форматирование строк в стиле printf.

END_OF_DOCUMENT_MARKER

7.2. Чтение и запись файлов

open() возвращает объект файла, и чаще всего используется с двумя позиционными аргументами и одним ключевым аргументом: open(filename, mode, encoding=None)

>>> f = open('workfile', 'w', encoding="utf-8")

Первый аргумент — строка, содержащая имя файла. Второй аргумент — ещё одна строка, содержащая несколько символов, описывающих способ использования файла. режим может быть 'r' для чтения, 'w' для записи (существующий файл с таким же именем будет удалён), и 'a' для добавления; любые данные, записанные в файл, автоматически добавляются в конец. 'r+' открывает файл для чтения и записи. Аргумент режим необязателен; 'r' будет принят по умолчанию, если он опущен.

Обычно файлы открываются в текстовом режиме, то есть вы читаете и пишете строки в и из файла, которые закодированы в определённой кодировке. Если кодировка не указана, используется кодировка по умолчанию, зависящая от платформы (см. open()). Поскольку UTF-8 является современным фактическим стандартом, encoding="utf-8" рекомендуется, если только вам не нужна другая кодировка. Добавление 'b' к режиму открывает файл в бинарном режиме. Данные в бинарном режиме читаются и записываются как bytes объекты. При открытии файла в бинарном режиме кодировку указать нельзя.

В текстовом режиме по умолчанию при чтении выполняется преобразование платформно-специфичных окончаний строк (\n в Unix, \r\n в Windows) в просто \n. При записи в текстовом режиме по умолчанию выполняется преобразование вхождения \n обратно в платформно-специфичные окончания строк. Эта скрытая модификация данных файла подходит для текстовых файлов, но повредит двоичные данные, как в JPEG или EXE файлах. Будьте очень осторожны, используя бинарный режим при чтении и записи таких файлов.

Хорошей практикой является использование ключевого слова with при работе с объектами файлов. Преимущество заключается в том, что файл корректно закрывается после завершения блока, даже если в какой-то момент возникает исключение. Использование with также намного короче, чем эквивалентные блоки try-finally:

>>> with open('workfile', encoding="utf-8") as f:
...     read_data = f.read()

>>> # We can check that the file has been automatically closed.
>>> f.closed
True

Если вы не используете ключевое слово with, то вы должны вызвать f.close() для закрытия файла и немедленного освобождения любых системных ресурсов, используемых им.

Предупреждение

Вызов f.write() без использования ключевого слова with или вызова f.close() может привести к тому, что аргументы f.write() не будут полностью записаны на диск, даже если программа завершится успешно.

После закрытия объекта файла, либо с помощью оператора with, либо вызовом f.close(), попытки использования объекта файла автоматически завершатся ошибкой.

>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.

7.2.1. Методы объектов файлов

Остальные примеры в этом разделе предполагают, что объект файла с именем f уже создан.

Для чтения содержимого файла вызовите f.read(size), которое считывает определённое количество данных и возвращает его в виде строки (в текстовом режиме) или объекта байтов (в бинарном режиме). размер — необязательный числовой аргумент. Когда размер опущен или отрицателен, читается и возвращается всё содержимое файла; если размер файла вдвое превышает объём памяти вашей машины, это ваша проблема. В противном случае читается и возвращается максимум размер символов (в текстовом режиме) или размер байтов (в бинарном режиме). Если достигнут конец файла, f.read() вернёт пустую строку ('').

>>> f.read()
'This is the entire file.\n'
>>> f.read()
''

f.readline() считывает одну строку из файла; символ новой строки (\n) оставляется в конце строки, и он опускается только в последней строке файла, если файл не заканчивается символом новой строки. Это делает возвращаемое значение однозначным; если f.readline() возвращает пустую строку, достигнут конец файла, а пустая строка представлена '\n', строкой, содержащей только одну новую строку.

>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''

Для чтения строк из файла можно использовать цикл по объекту файла. Это эффективно с точки зрения памяти, быстро и приводит к простому коду:

>>> for line in f:
...     print(line, end='')
...
This is the first line of the file.
Second line of the file

Если вы хотите прочитать все строки файла в список, вы также можете использовать list(f) или f.readlines().

f.write(string) записывает содержимое строки в файл, возвращая количество записанных символов.

>>> f.write('This is a test\n')
15

Другие типы объектов необходимо преобразовать — либо в строку (в текстовом режиме), либо в объект байтов (в бинарном режиме) — перед записью:

>>> value = ('the answer', 42)
>>> s = str(value)  # convert the tuple to string
>>> f.write(s)
18

f.tell() возвращает целое число, представляющее текущую позицию объекта файла в файле, как количество байтов от начала файла в бинарном режиме и некое значение в текстовом режиме.

Для изменения позиции объекта файла используйте f.seek(offset, whence). Позиция вычисляется путём добавления смещения к точке отсчёта; точка отсчёта выбирается аргументом whence. Значение whence 0 измеряет с начала файла, 1 использует текущую позицию файла, а 2 использует конец файла как точку отсчёта. whence может быть опущено и по умолчанию равно 0, используя начало файла как точку отсчёта.

>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)      # Go to the 6th byte in the file
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2)  # Go to the 3rd byte before the end
13
>>> f.read(1)
b'd'

В текстовых файлах (открытых без b в строке режима) разрешается только поиск, относительно начала файла (исключение составляет поиск в конец файла с seek(0, 2)) и единственные допустимые значения смещения — те, что возвращаются функцией f.tell(), или нуль. Любое другое значение смещения приводит к неопределённому поведению.

Объекты файлов имеют дополнительные методы, такие как isatty() и truncate(), которые используются реже; обратитесь к Справочнику по библиотеке за полным руководством по объектам файлов.

7.2.2. Сохранение структурированных данных с помощью json

Строки легко записываются в файл и считываются из него. Для чисел требуется немного больше усилий, так как метод read() возвращает только строки, которые необходимо передать функции, такой как int(), которая принимает строку, например, '123', и возвращает ее числовое значение 123. При работе с более сложными типами данных, такими как вложенные списки и словари, ручная обработка парсинга и сериализации становится сложной.

Вместо того, чтобы пользователи постоянно писали и отлаживали код для сохранения сложных типов данных в файлы, Python позволяет использовать популярный формат обмена данными под названием JSON (JavaScript Object Notation). Стандартный модуль под названием json может принимать иерархии данных Python и преобразовывать их в строковые представления; этот процесс называется сериализацией. Восстановление данных из строкового представления называется десериализацией. Между сериализацией и десериализацией строковое представление объекта может храниться в файле или данных, или отправляться по сетевому соединению на удаленный компьютер.

Примечание

Формат JSON широко используется современными приложениями для обмена данными. Многие программисты уже знакомы с ним, что делает его хорошим выбором для межплатформенного взаимодействия.

Если у вас есть объект x, вы можете просмотреть его JSON-строковое представление с помощью одной простой строки кода:

>>> import json
>>> x = [1, 'simple', 'list']
>>> json.dumps(x)
'[1, "simple", "list"]'

Другая разновидность функции dumps(), называемая dump(), просто сериализует объект в текстовый файл. Таким образом, если f — это объект текстового файла, открытый для записи, мы можем сделать это:

json.dump(x, f)

Чтобы снова декодировать объект, если f — это объект бинарного файла или текстового файла, который был открыт для чтения:

x = json.load(f)

Примечание

JSON-файлы должны быть закодированы в UTF-8. Используйте encoding="utf-8" при открытии JSON-файла как текстового файла для чтения и записи.

Эта простая техника сериализации может обрабатывать списки и словари, но сериализация произвольных экземпляров классов в JSON требует дополнительных усилий. Справочник по модулю json содержит объяснение этого.

См. также

pickle — модуль pickle

В отличие от JSON, pickle — это протокол, который позволяет сериализовать произвольно сложные объекты Python. Таким образом, он специфичен для Python и не может использоваться для связи с приложениями, написанными на других языках. Кроме того, по умолчанию он небезопасен: десериализация данных pickle, полученных из ненадежного источника, может выполнить произвольный код, если данные были созданы опытным злоумышленником.

© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.9/tutorial/inputoutput.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API