Ввод и вывод
Существует несколько способов представить вывод программы; данные могут быть напечатаны в удобочитаемой форме или записаны в файл для последующего использования. В этой главе будут обсуждены некоторые возможности.
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 >>> total_votes = 85_705_149 >>> percentage = yes_votes / total_votes >>> '{:-9} YES votes {:2.2%}'.format(yes_votes, percentage) ' 42572654 YES votes 49.67%'Обратите внимание, как
yes_votesвыравниваются по правому краю с пробелами и знак минус присутствует только для отрицательных чисел. Пример также выводит значениеpercentage, умноженное на 100, с 2 знаками после запятой и знаком процента (см. Минимальный язык спецификаций форматирования для получения подробной информации). - Наконец, вы можете выполнить все манипуляции со строками самостоятельно, используя операции срезов и конкатенации строк, чтобы создать любой макет, который вы можете себе представить. Тип строки имеет некоторые методы, которые выполняют полезные операции для выравнивания строк до заданной ширины столбца.
Когда вам не нужен сложный вывод, а просто требуется быстрое отображение некоторых переменных для отладки, вы можете преобразовать любое значение в строку с помощью функций 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'.
Спецификатор = может использоваться для расширения выражения до текста выражения, знака равенства и представления вычисленного выражения:
>>> bugs = 'roaches'
>>> count = 13
>>> area = 'living room'
>>> print(f'Debugging {bugs=} {count=} {area=}')
Debugging bugs='roaches' count=13 area='living room'
См. самодокументированные выражения для получения дополнительной информации о спецификаторе =. Для справки по этим спецификациям форматирования см. справочное руководство по Минимальному языку спецификаций форматирования.
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 словарь как ключевые аргументы с использованием обозначения **.
>>> 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(), которая возвращает словарь, содержащий все локальные переменные:
>>> table = {k: str(v) for k, v in vars().items()}
>>> message = " ".join([f'{k}: ' + '{' + k +'};' for k in table.keys()])
>>> print(message.format(**table))
__name__: __main__; __doc__: None; __package__: None; __loader__: ...
В качестве примера, следующие строки генерируют аккуратно выровненные столбцы, которые дают целые числа и их квадраты и кубы:
>>> 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. Старое форматирование строк
Оператор % (модуль) также может использоваться для форматирования строк. Учитывая format % values (где format — строка), спецификации преобразования % в format заменяются одним или несколькими элементами 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, encoding=None)
>>> f = open('workfile', 'w', encoding="utf-8")
Первый аргумент — строка, содержащая имя файла. Второй аргумент — еще одна строка, содержащая несколько символов, описывающих способ использования файла. mode может быть 'r' , если файл будет только читаться, 'w' для записи (существующий файл с тем же именем будет удален), и 'a' открывает файл для добавления; любые данные, записанные в файл, автоматически добавляются в конец. 'r+' открывает файл как для чтения, так и для записи. Аргумент mode необязателен; '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), который считывает некоторое количество данных и возвращает его в виде строки (в текстовом режиме) или объекта bytes (в двоичном режиме). 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) записывает содержимое строки в файл, возвращая количество записанных символов.
>>> f.write('This is a test\n')
15
Другие типы объектов необходимо преобразовать — либо в строку (в текстовом режиме), либо в объект bytes (в двоичном режиме) — перед записью:
>>> 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–2024 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.13/tutorial/inputoutput.html