Spec-Zone.ru › Python 3.12

Ввод и вывод

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

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, с двумя десятичными знаками и последующим знаком процента (подробности см. в разделе Форматный язык мини-языка).

  • Наконец, вы можете самостоятельно выполнить все операции со строками, используя операции срезов и конкатенации для создания любого желаемого макета. Тип строки имеет некоторые методы, которые выполняют полезные операции для выравнивания строк по заданной ширине столбца.

Когда вам не нужен сложный вывод, а нужно только быстро отобразить некоторые переменные для отладки, вы можете преобразовать любое значение в строку с помощью функций 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. Старое форматирование строк

Оператор % (modulo) также может использоваться для форматирования строк. В данном случае 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. encoding не может быть указан при открытии файла в бинарном режиме.

В текстовом режиме по умолчанию при чтении выполняется преобразование специфичных для платформы символов конца строки (\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), который считывает некоторое количество данных и возвращает его как строку (в текстовом режиме) или объект байтов (в бинарном режиме). 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
>>> 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.12/tutorial/inputoutput.html

Spec-Zone.ru

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