Spec-Zone.ru › Python 3.10

Ввод и вывод

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

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'.

Спецификатор = может использоваться для расширения выражения до текста выражения, знака равенства и представления вычисленного выражения:

>>> 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(), которая возвращает словарь, содержащий все локальные переменные.

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

>>> 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, 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), который считывает некоторое количество данных и возвращает его в виде строки (в текстовом режиме) или объекта байтов (в двоичном режиме). 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–2023 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.10/tutorial/inputoutput.html

Spec-Zone.ru

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