Spec-Zone.ru › Python 3.14

Ввод и вывод

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

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 поддерживает простой подход к шаблонам на основе регулярных выражений с помощью 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'.

Обычно файлы открываются в текстовом режиме: это означает, что из файла читаются и в файл записываются строки, закодированные с помощью определённой кодировки. Если 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). Стандартный модуль 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 Python Software Foundation
Licensed under the PSF License.
https://docs.python.org/3.14/tutorial/inputoutput.html

Spec-Zone.ru

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