Spec-Zone.ru › Python 3.13

Ввод и вывод

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

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

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

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

Обычно файлы открываются в текстовом режиме: строки читаются из файла и записываются в него с использованием определённой кодировки. Если encoding не задан, кодировка по умолчанию зависит от платформы (см. 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). Метод считывает некоторое количество данных и возвращает их в виде строки (в текстовом режиме) или объекта 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) записывает содержимое 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). Позиция вычисляется как сумма 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 — нотация объектов JavaScript). Стандартный модуль 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. При открытии JSON-файла как текстового файла для чтения или записи используйте encoding="utf-8".

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

См. также

pickle — модуль pickle

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

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

Spec-Zone.ru

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