Ввод и вывод
Существует несколько способов представления вывода программы; данные могут быть напечатаны в удобочитаемой форме или записаны в файл для последующего использования. В этой главе будут рассмотрены некоторые возможности.
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. Старое форматирование строк
Оператор % (modulo) также может быть использован для форматирования строк. Ввиду '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.
7.2. Чтение и запись файлов
open() возвращает объект файла, и чаще всего используется с двумя аргументами: open(filename, mode).
>>> f = open('workfile', 'w')
Первый аргумент — строка, содержащая имя файла. Второй аргумент — ещё одна строка, содержащая несколько символов, описывающих способ использования файла. mode может быть 'r' при чтении, 'w' для записи (существующий файл с таким же именем будет удалён), и 'a' открывает файл для добавления; любые данные, записанные в файл, автоматически добавляются в конец. 'r+' открывает файл для чтения и записи. Аргумент mode является необязательным; 'r' будет предположено, если он опущен.
Обычно файлы открываются в текстовом режиме, то есть вы читаете и записываете строки в и из файла, которые закодированы в определённой кодировке. Если кодировка не указана, по умолчанию используется кодировка, зависящая от платформы (см. open()). 'b' добавляется к режиму, открывает файл в бинарном режиме: теперь данные читаются и записываются в виде объектов байтов. Этот режим следует использовать для всех файлов, которые не содержат текста.
В текстовом режиме, по умолчанию при чтении, выполняются преобразования специфичных для платформы конечных символов строки (\n в Unix, \r\n в Windows) в просто \n. При записи в текстовом режиме, по умолчанию, преобразование \n возвращается в специфичные для платформы конечные символы строки. Это скрытое изменение данных файла подходит для текстовых файлов, но повредит двоичные данные, такие как в JPEG или EXE файлах. Будьте очень осторожны, используйте бинарный режим при чтении и записи таких файлов.
Хорошей практикой является использование ключевого слова with при работе с объектами файла. Преимущество состоит в том, что файл правильно закрывается после завершения его блока, даже если в какой-то момент произойдёт исключение. Использование with также намного короче, чем написание эквивалентных блоков try-finally:
>>> with open('workfile') 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), который считывает некоторое количество данных и возвращает их в виде строки (в текстовом режиме) или объекта байтов (в бинарном режиме). size — необязательный числовой аргумент. Если size опущен или отрицателен, будет считано и возвращено всё содержимое файла; это ваша проблема, если файл вдвое больше памяти вашей машины. В противном случае, не более size символов (в текстовом режиме) или 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) записывает содержимое 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). Позиция вычисляется путём добавления offset к точке отсчёта; точка отсчёта выбирается аргументом 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)) и только допустимые значения offset возвращаемые из f.tell(), или ноль. Любое другое значение offset приводит к неопределённому поведению.
Объекты файлов имеют дополнительные методы, такие как isatty() и truncate(), которые используются реже; обратитесь к Справочнику по библиотеке за полным руководством по объектам файлов.
7.2.2. Сохранение структурированных данных с помощью json
Строки легко записываются в файл и считываются из файла. Числа требуют несколько больше усилий, так как метод read() возвращает только строки, которые необходимо передавать в функцию, такую как int(), которая принимает строку, такую как '123' и возвращает её числовое значение 123. Когда вы хотите сохранить более сложные типы данных, такие как вложенные списки и словари, ручная обработка и сериализация становится сложной.
Вместо того, чтобы пользователи постоянно писали и отлаживали код для сохранения сложных типов данных в файлах, Python позволяет вам использовать популярный формат обмена данными под названием JSON (JavaScript Object Notation). Стандартный модуль под названием json может принимать иерархии данных Python и преобразовывать их в строковые представления; этот процесс называется сериализацией. Восстановление данных из строкового представления называется десериализацией. Между сериализацией и десериализацией строковое представление объекта может быть сохранено в файле или данных, или отправлено по сетевому соединению на удалённый компьютер.
Примечание
Формат JSON часто используется современными приложениями для обмена данными. Многие программисты уже знакомы с ним, что делает его хорошим выбором для взаимодействия.
Если у вас есть объект x, вы можете просмотреть его строковое представление JSON с помощью одной простой строки кода:
>>> import json >>> json.dumps([1, 'simple', 'list']) '[1, "simple", "list"]'
Другой вариант функции dumps(), с именем dump(), просто сериализует объект в текстовый файл. Итак, если f — это объект текстового файла, открытый для записи, мы можем сделать это:
json.dump(x, f)
Для повторного декодирования объекта, если f — это объект текстового файла, открытый для чтения:
x = json.load(f)
Этот простой метод сериализации может обрабатывать списки и словари, но сериализация произвольных экземпляров классов в JSON требует немного дополнительных усилий. Справочник по модулю json содержит объяснение этого.
См. также
pickle — модуль pickle
В отличие от JSON, pickle — это протокол, который позволяет сериализовать произвольно сложные объекты Python. Как таковой, он специфичен для Python и не может использоваться для общения с приложениями, написанными на других языках. Он также небезопасен по умолчанию: десериализация данных pickle, поступающих из ненадежного источника, может выполнить произвольный код, если данные были созданы квалифицированным злоумышленником.
© 2001–2022 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.8/tutorial/inputoutput.html