Документация Python неофициальный перевод
Содержание страницы

7. Ввод и выводInput and Output

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

7.1. Более изощрённое форматирование выводаFancier Output Formatting

До сих пор мы встречали два способа вывода значений: инструкции-выражения и инструкция print. (Третий способ – использовать метод write() файловых объектов; стандартный выходной файл можно обозначить как sys.stdout. Дополнительную информацию можно найти в Справочнике по библиотеке.)

Часто требуется более точное управление форматированием вывода, чем просто печать значений, разделённых пробелами. Существует два способа форматирования вывода: первый – выполнить всю обработку строк самостоятельно; используя операции извлечения подстрок и конкатенации, можно создать любой макет. Строковые типы имеют несколько методов, выполняющих полезные операции по дополнению строк до заданной ширины столбца; они будут рассмотрены далее. Второй способ – использовать метод str.format().

Модуль string содержит класс Template, который предлагает ещё один способ подстановки значений в строки.

Остаётся, конечно, один вопрос: как преобразовать значения в строки? К счастью, в Python есть способы преобразовать любое значение в строку: передать его функциям repr() или str().

Функция str() предназначена для возврата представлений значений, которые достаточно читаемы для человека, в то время как repr() предназначена для генерации представлений, которые могут быть прочитаны интерпретатором (или вызовет SyntaxError, если нет эквивалентного синтаксиса). Для объектов, не имеющих специального представления для человека, str() вернёт то же значение, что и repr(). Многие значения, такие как числа или структуры вроде списков и словарей, имеют одинаковое представление при использовании любой функции. Строки и числа с плавающей точкой, в частности, имеют два различных представления.

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

>>> s = 'Hello, world.'
>>> str(s)
'Hello, world.'
>>> repr(s)
"'Hello, world.'"
>>> str(1.0/7.0)
'0.142857142857'
>>> repr(1.0/7.0)
'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'))"

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

>>> for x in range(1, 11):
...     print repr(x).rjust(2), repr(x*x).rjust(3),
...     # Примечание: завершающая запятая на предыдущей строке
...     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: по умолчанию он добавляет пробелы между своими аргументами.)

Этот пример демонстрирует метод 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'

Базовое использование метода 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.

'!s' (применить str()) и '!r' (применить repr()) можно использовать для преобразования значения перед форматированием.

>>> import math
>>> print 'The value of PI is approximately {}.'.format(math.pi)
The value of PI is approximately 3.14159265359.
>>> print 'The value of PI is approximately {!r}.'.format(math.pi)
The value of PI is approximately 3.141592653589793.

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

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

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

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

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

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

Полный обзор форматирования строк с помощью str.format() см. в Синтаксисе строк форматирования.

7.1.1. Старое форматирование строкOld string formatting

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

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

Дополнительную информацию можно найти в разделе Операции форматирования строк.

7.2. Чтение и запись файловReading and Writing Files

open() возвращает файловый объект и чаще всего используется с двумя аргументами: open(filename, mode).

>>> f = open('workfile', 'w')
>>> print f
<open file 'workfile', mode 'w' at 80a0960>

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

В Windows добавление 'b' к режиму открывает файл в двоичном режиме, поэтому существуют также режимы 'rb', 'wb' и 'r+b'. Python в Windows различает текстовые и двоичные файлы; символы конца строки в текстовых файлах автоматически слегка изменяются при чтении или записи данных. Это скрытое изменение данных файла нормально для текстовых файлов ASCII, но повредит двоичные данные, например, в файлах JPEG или EXE. Требуется особая осторожность при использовании двоичного режима для чтения и записи таких файлов. В Unix добавление 'b' к режиму не вредит, поэтому его можно использовать независимо от платформы для всех двоичных файлов.

7.2.1. Методы файловых объектовMethods of File Objects

Остальные примеры в этом разделе предполагают, что файловый объект с именем f уже создан.

Чтобы прочитать содержимое файла, вызовите f.read(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,

This is the first line of the file.
Second line of the file

Если нужно прочитать все строки файла в виде списка, можно также использовать list(f) или f.readlines().

f.write(string) записывает содержимое string в файл и возвращает None.

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

Чтобы записать что-то, отличное от строки, его сначала нужно преобразовать в строку:

>>> value = ('the answer', 42)
>>> s = str(value)
>>> f.write(s)

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

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

Когда работа с файлом завершена, вызовите f.close(), чтобы закрыть его и освободить все системные ресурсы, занятые открытым файлом. После вызова f.close() попытки использовать файловый объект будут автоматически завершаться ошибкой.

>>> f.close()
>>> f.read()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file

Рекомендуется использовать ключевое слово with при работе с файловыми объектами. Это гарантирует, что файл будет корректно закрыт после завершения своего блока, даже если возникнет исключение. Кроме того, это гораздо короче, чем писать эквивалентные блоки try-finally:

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

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

7.2.2. Сохранение структурированных данных с помощью jsonSaving structured data with json

Строки можно легко записать в файл и прочитать из файла. С числами немного сложнее, поскольку метод read() возвращает только строки, которые затем нужно передать такой функции, как int(), принимающей строку вида '123' и возвращающей её числовое значение 123. Если требуется сохранять более сложные типы данных, например вложенные списки и словари, ручной разбор и сериализация становятся сложными.

Чтобы избавить пользователей от постоянного написания и отладки кода для сохранения сложных типов данных в файлы, Python позволяет использовать популярный формат обмена данными, называемый JSON (JavaScript Object Notation). Стандартный модуль json может обрабатывать иерархии данных Python и преобразовывать их в строковые представления; этот процесс называется сериализацией. Восстановление данных из строкового представления называется десериализацией. Между сериализацией и десериализацией строка, представляющая объект, может быть сохранена в файл или данные, либо передана по сетевому соединению на удалённую машину.

Примечание

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

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

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

Другой вариант функции dumps(), называемый dump(), просто сериализует объект в файл. Так, если f – это файловый объект, открытый для записи, можно сделать следующее:

json.dump(x, f)

Чтобы снова декодировать объект, если f – это файловый объект, открытый для чтения:

x = json.load(f)

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

См. также

pickle – модуль pickle

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