> **Источник:** https://python-all.ru/3.5/tutorial/inputoutput.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# 7. Ввод и вывод

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

## 7.1. Расширенное форматирование вывода

До сих пор мы встречали два способа записи значений: *инструкции-выражения* и функция [`print()`](https://python-all.ru/3.5/library/functions.html#print). (Третий способ – использовать метод `write()` файловых объектов; стандартный файл вывода можно указать как `sys.stdout`. Подробнее об этом см. в Справочнике по библиотеке.)

Часто возникает необходимость более тонко контролировать форматирование вывода, чем просто печать значений через пробел. Есть два способа форматирования вывода: первый – выполнять всю обработку строк самостоятельно; используя срезы строк и конкатенацию, можно создать любой макет. Тип ⟦str⟧ имеет несколько методов, выполняющих полезные операции для дополнения строк до заданной ширины столбца, – они будут рассмотрены чуть позже. Второй способ – использовать метод [`str.format()`](https://python-all.ru/3.5/library/stdtypes.html#str.format).

Модуль [`string`](https://python-all.ru/3.5/library/string.html#module-string) содержит класс [`Template`](https://python-all.ru/3.5/library/string.html#string.Template), который предлагает ещё один способ подстановки значений в строки.

Остаётся, конечно, один вопрос: как преобразовать значения в строки? К счастью, в Python есть способы преобразовать любое значение в строку: передать его функциям [`repr()`](https://python-all.ru/3.5/library/functions.html#repr) или [`str()`](https://python-all.ru/3.5/library/stdtypes.html#str).

Функция [`str()`](https://python-all.ru/3.5/library/stdtypes.html#str) предназначена для возврата представлений значений, которые достаточно удобочитаемы, тогда как [`repr()`](https://python-all.ru/3.5/library/functions.html#repr) предназначена для создания представлений, которые могут быть прочитаны интерпретатором (или вызовет [`SyntaxError`](https://python-all.ru/3.5/library/exceptions.html#SyntaxError), если нет эквивалентного синтаксиса). Для объектов, не имеющих специального представления для человека, [`str()`](https://python-all.ru/3.5/library/stdtypes.html#str) вернёт то же значение, что и [`repr()`](https://python-all.ru/3.5/library/functions.html#repr). Многие значения, такие как числа или структуры вроде списков и словарей, имеют одинаковое представление при использовании любой функции. Строки, в частности, имеют два различных представления.

Несколько примеров:

```python
>>> 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...
>>> # repr() строки добавляет кавычки и обратную косую черту:
... hello = 'hello, world\n'
>>> hellos = repr(hello)
>>> print(hellos)
'hello, world\n'
>>> # Аргументом repr() может быть любой объект Python:
... repr((x, y, ('spam', 'eggs')))
"(32.5, 40000, ('spam', 'eggs'))"
```

Вот два способа вывести таблицу квадратов и кубов:

```python
>>> for x in range(1, 11):
...     print(repr(x).rjust(2), repr(x*x).rjust(3), end=' ')
...     # Обратите внимание на использование 'end' в предыдущей строке
...     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

>>> 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
```

(Обратите внимание, что в первом примере один пробел между столбцами был добавлен тем, как работает [`print()`](https://python-all.ru/3.5/library/functions.html#print): он всегда добавляет пробелы между своими аргументами.)

Этот пример демонстрирует метод [`str.rjust()`](https://python-all.ru/3.5/library/stdtypes.html#str.rjust) строковых объектов, который выравнивает строку по правому краю в поле заданной ширины, дополняя её пробелами слева. Существуют аналогичные методы [`str.ljust()`](https://python-all.ru/3.5/library/stdtypes.html#str.ljust) и [`str.center()`](https://python-all.ru/3.5/library/stdtypes.html#str.center). Эти методы ничего не выводят, они просто возвращают новую строку. Если входная строка слишком длинная, они не обрезают её, а возвращают без изменений; это может испортить выравнивание столбцов, но обычно это лучше, чем альтернатива – искажать значение. (Если обрезка действительно нужна, всегда можно добавить срез, как в `x.ljust(n)[:n]`.)

Существует ещё один метод, [`str.zfill()`](https://python-all.ru/3.5/library/stdtypes.html#str.zfill), который дополняет числовую строку слева нулями. Он учитывает знаки плюс и минус:

```python
>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'
```

Базовое использование метода [`str.format()`](https://python-all.ru/3.5/library/stdtypes.html#str.format) выглядит так:

```python
>>> print('We are the {} who say "{}!"'.format('knights', 'Ni'))
We are the knights who say "Ni!"
```

Скобки и символы внутри них (называемые полями формата) заменяются на объекты, переданные методу [`str.format()`](https://python-all.ru/3.5/library/stdtypes.html#str.format). Число в скобках можно использовать для указания позиции объекта, переданного методу [`str.format()`](https://python-all.ru/3.5/library/stdtypes.html#str.format).

```python
>>> print('{0} and {1}'.format('spam', 'eggs'))
spam and eggs
>>> print('{1} and {0}'.format('spam', 'eggs'))
eggs and spam
```

Если в методе [`str.format()`](https://python-all.ru/3.5/library/stdtypes.html#str.format) используются именованные аргументы, на их значения ссылаются по имени аргумента.

```python
>>> print('This {food} is {adjective}.'.format(
...       food='spam', adjective='absolutely horrible'))
This spam is absolutely horrible.
```

Позиционные и именованные аргументы можно произвольно комбинировать:

```python
>>> print('The story of {0}, {1}, and {other}.'.format('Bill', 'Manfred',
                                                       other='Georg'))
The story of Bill, Manfred, and Georg.
```

`'!a'` (применить [`ascii()`](https://python-all.ru/3.5/library/functions.html#ascii)), `'!s'` (применить [`str()`](https://python-all.ru/3.5/library/stdtypes.html#str)) и `'!r'` (применить [`repr()`](https://python-all.ru/3.5/library/functions.html#repr)) можно использовать для преобразования значения перед форматированием:

```python
>>> contents = 'eels'
>>> print('My hovercraft is full of {}.'.format(contents))
My hovercraft is full of eels.
>>> print('My hovercraft is full of {!r}.'.format(contents))
My hovercraft is full of 'eels'.
```

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

```python
>>> import math
>>> print('The value of PI is approximately {0:.3f}.'.format(math.pi))
The value of PI is approximately 3.142.
```

Передача целого числа после `':'` задаёт минимальную ширину поля в символах. Это удобно для красивых таблиц.

```python
>>> table = {'Sjoerd': 4127, 'Jack': 4098, 'Dcab': 7678}
>>> for name, phone in table.items():
...     print('{0:10} ==> {1:10d}'.format(name, phone))
...
Jack       ==>       4098
Dcab       ==>       7678
Sjoerd     ==>       4127
```

Если у вас очень длинная строка форматирования, которую не хочется разбивать, было бы удобно ссылаться на переменные по имени, а не по позиции. Это можно сделать, просто передав словарь и используя квадратные скобки `'[]'` для доступа к ключам.

```python
>>> 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
```

Это также можно сделать, передав таблицу как именованные аргументы с помощью нотации ‘\*\*’ .

```python
>>> 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()`](https://python-all.ru/3.5/library/functions.html#vars), которая возвращает словарь, содержащий все локальные переменные.

Полный обзор форматирования строк с помощью [`str.format()`](https://python-all.ru/3.5/library/stdtypes.html#str.format) см. в [Синтаксисе строк форматирования](https://python-all.ru/3.5/library/string.html#formatstrings).

### 7.1.1. Старое форматирование строк

Оператор `%` также можно использовать для форматирования строк. Он интерпретирует левый аргумент как строку формата в стиле `sprintf()`, которая применяется к правому аргументу, и возвращает строку, полученную в результате форматирования. Например:

```python
>>> import math
>>> print('The value of PI is approximately %5.3f.' % math.pi)
The value of PI is approximately 3.142.
```

Дополнительную информацию можно найти в разделе [Форматирование строк в стиле printf](https://python-all.ru/3.5/library/stdtypes.html#old-string-formatting).

## 7.2. Чтение и запись файлов

[`open()`](https://python-all.ru/3.5/library/functions.html#open) возвращает [файловый объект](https://python-all.ru/3.5/glossary.html#term-file-object) и чаще всего используется с двумя аргументами: `open(filename, mode)`.

```python
>>> f = open('workfile', 'w')
```

Первый аргумент – строка, содержащая имя файла. Второй аргумент – ещё одна строка, содержащая несколько символов, описывающих способ использования файла. *mode* может быть `'r'` для чтения, `'w'` только для записи (существующий файл с таким же именем будет стёрт), а `'a'` открывает файл для дополнения; любые записанные данные автоматически добавляются в конец. `'r+'` открывает файл и для чтения, и для записи. Аргумент *mode* необязателен; если он опущен, предполагается `'r'`.

Обычно файлы открываются в *текстовом режиме*, что означает чтение и запись строк в файл и из файла, которые закодированы в определённой кодировке. Если кодировка не указана, используется платформозависимая по умолчанию (см. [`open()`](https://python-all.ru/3.5/library/functions.html#open)). Добавление `'b'` к режиму открывает файл в *двоичном режиме*: теперь данные читаются и записываются в виде объектов bytes. Этот режим следует использовать для всех файлов, не содержащих текст.

В текстовом режиме при чтении по умолчанию концевые символы строки, зависящие от платформы (`\n` в Unix, `\r\n` в Windows), преобразуются в простой `\n`. При записи в текстовом режиме по умолчанию вхождения `\n` преобразуются обратно в концевые символы, зависящие от платформы. Эта фоновая модификация данных файла нормальна для текстовых файлов, но повредит двоичные данные, например, в файлах `JPEG` или `EXE`. Будьте очень осторожны и используйте двоичный режим при чтении и записи таких файлов.

Рекомендуется использовать ключевое слово [`with`](https://python-all.ru/3.5/reference/compound_stmts.html#with) при работе с файловыми объектами. Преимущество в том, что файл корректно закрывается после завершения своего блока, даже если в какой-то момент возникло исключение. Использование [`with`](https://python-all.ru/3.5/reference/compound_stmts.html#with) также намного короче, чем написание эквивалентных блоков [`try`](https://python-all.ru/3.5/reference/compound_stmts.html#try)-[`finally`](https://python-all.ru/3.5/reference/compound_stmts.html#finally):

```python
>>> with open('workfile') as f:
...     read_data = f.read()
>>> f.closed
True
```

Если ключевое слово [`with`](https://python-all.ru/3.5/reference/compound_stmts.html#with) не используется, следует вызвать `f.close()`, чтобы закрыть файл и немедленно освободить все занятые им системные ресурсы. Если файл не закрыть явно, сборщик мусора Python в конечном счёте уничтожит объект и закроет открытый файл, но файл может оставаться открытым некоторое время. Ещё один риск – разные реализации Python могут выполнять эту очистку в разное время.

После закрытия файлового объекта – с помощью инструкции [`with`](https://python-all.ru/3.5/reference/compound_stmts.html#with) или вызова `f.close()` – попытки использовать файловый объект автоматически завершатся неудачей.

```python
>>> 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 (в двоичном режиме). *размер* – необязательный числовой аргумент. Если *размер* опущен или отрицателен, будет прочитано и возвращено всё содержимое файла; если файл в два раза больше оперативной памяти – это ваша проблема. В противном случае считывается и возвращается не более *размер* байт. Если достигнут конец файла, `f.read()` вернёт пустую строку (`''`).

```python
>>> f.read()
'This is the entire file.\n'
>>> f.read()
''
```

`f.readline()` читает одну строку из файла; символ новой строки (`\n`) остаётся в конце строки и опускается только в последней строке файла, если файл не заканчивается переводом строки. Это делает возвращаемое значение однозначным: если `f.readline()` возвращает пустую строку, конец файла достигнут, тогда как пустая строка представляется как `'\n'`, строка, содержащая только один символ новой строки.

```python
>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''
```

Для чтения строк из файла можно выполнять итерацию по файловому объекту. Это эффективно по памяти, быстро и приводит к простому коду:

```python
>>> 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* в файл и возвращает количество записанных символов.

```python
>>> f.write('This is a test\n')
15
```

Объекты других типов необходимо преобразовать – либо в строку (в текстовом режиме), либо в объект bytes (в двоичном режиме) – перед записью:

```python
>>> value = ('the answer', 42)
>>> s = str(value)  # преобразовать кортеж в строку
>>> f.write(s)
18
```

`f.tell()` возвращает целое число, указывающее текущую позицию в файле для данного файлового объекта, представленную как количество байтов от начала файла в двоичном режиме и непрозрачное число в текстовом режиме.

Чтобы изменить позицию файлового объекта, используйте `f.seek(offset, from_what)`. Позиция вычисляется прибавлением *смещение* к опорной точке; опорная точка выбирается аргументом *from\_what*. Значение *from\_what* равное 0 задаёт начало файла, 1 – текущую позицию, а 2 – конец файла в качестве опорной точки. Параметр *from\_what* можно опустить; по умолчанию он равен 0, то есть опорная точка – начало файла.

```python
>>> f = open('workfile', 'rb+')
>>> f.write(b'0123456789abcdef')
16
>>> f.seek(5)      # Перейти к 6-му байту в файле
5
>>> f.read(1)
b'5'
>>> f.seek(-3, 2)  # Перейти к 3-му байту от конца
13
>>> f.read(1)
b'd'
```

В текстовых файлах (открытых без `b` в строке режима) разрешены только позиционирования относительно начала файла (исключение – позиционирование в самый конец файла с помощью `seek(0, 2)`), и единственные допустимые значения *offset* – это те, что возвращены `f.tell()`, или ноль. Любое другое значение *offset* приводит к неопределённому поведению.

Файловые объекты имеют некоторые дополнительные методы, такие как `isatty()` и `truncate()`, которые используются реже; обратитесь к Справочнику библиотеки для получения полного руководства по файловым объектам.

### 7.2.2. Сохранение структурированных данных с помощью [`json`](https://python-all.ru/3.5/library/json.html#module-json)

Строки можно легко записать в файл и прочитать из файла. С числами немного сложнее, поскольку метод `read()` возвращает только строки, которые затем нужно передать такой функции, как [`int()`](https://python-all.ru/3.5/library/functions.html#int), принимающей строку вида `'123'` и возвращающей её числовое значение 123. Если требуется сохранять более сложные типы данных, например вложенные списки и словари, ручной разбор и сериализация становятся сложными.

Чтобы избавить пользователей от постоянного написания и отладки кода для сохранения сложных типов данных в файлы, Python позволяет использовать популярный формат обмена данными, называемый [JSON (JavaScript Object Notation)](https://python-all.ru/3.5/tutorial/inputoutput.html). Стандартный модуль [`json`](https://python-all.ru/3.5/library/json.html#module-json) может обрабатывать иерархии данных Python и преобразовывать их в строковые представления; этот процесс называется *сериализацией*. Восстановление данных из строкового представления называется *десериализацией*. Между сериализацией и десериализацией строка, представляющая объект, может быть сохранена в файл или данные, либо передана по сетевому соединению на удалённую машину.

> **Примечание**
>
> Формат JSON широко используется в современных приложениях для обмена данными. Многие программисты уже знакомы с ним, что делает его хорошим выбором для обеспечения совместимости.

Если у вас есть объект `x`, вы можете увидеть его строковое представление в JSON одной строкой кода:

```python
>>> import json
>>> json.dumps([1, 'simple', 'list'])
'[1, "simple", "list"]'
```

Другой вариант функции [`dumps()`](https://python-all.ru/3.5/library/json.html#json.dumps), называемый [`dump()`](https://python-all.ru/3.5/library/json.html#json.dump), просто сериализует объект в [текстовый файл](https://python-all.ru/3.5/glossary.html#term-text-file). Так что если `f` – это [текстовый файл](https://python-all.ru/3.5/glossary.html#term-text-file), открытый для записи, можно сделать следующее:

```python
json.dump(x, f)
```

Чтобы снова декодировать объект, если `f` – это [объект текстового файла](https://python-all.ru/3.5/glossary.html#term-text-file), открытого для чтения:

```python
x = json.load(f)
```

Этот простой метод сериализации может обрабатывать списки и словари, но для сериализации произвольных экземпляров классов в JSON требуется немного дополнительных усилий. В справочнике по модулю [`json`](https://python-all.ru/3.5/library/json.html#module-json) есть объяснение этого.

> **См. также**
>
> [`pickle`](https://python-all.ru/3.5/library/pickle.html#module-pickle) – модуль pickle
>
> В отличие от [JSON](https://python-all.ru/3.5/tutorial/inputoutput.html#tut-json), *pickle* – это протокол, позволяющий сериализовывать произвольно сложные объекты Python. Поэтому он специфичен для Python и не может использоваться для взаимодействия с приложениями, написанными на других языках. Кроме того, по умолчанию он небезопасен: десериализация данных pickle из ненадёжного источника может выполнить произвольный код, если данные были подготовлены опытным злоумышленником.
