Информационные технологииStfw.Ru 🔍

Ввод/вывод

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

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

Часто возникает желание иметь больший контроль над форматированием вывода, чем просто выводить значения, разделенные пробелом. Конечно, Вы можете сами обрабатывать строки: с помощью операций среза и объединения можно создать любое расположение, какое только Вы сможете представить. Строки имеют методы, позволяющие дополнять их пробелами до необходимой ширины колонки [Эти методы строк появились в версии 1.6 языка Python. В предыдущих версия они доступны в виде функций, определенных в модуле string.]. Другой путь - использовать оператор % со строкой в качестве левого аргумента. Оператор % интерпретирует строку справа как строку формата в стиле функции sprintf() в C, которую нужно применить к правому аргументу, и возвращает строку с результатом форматирования.

Безусловно, остается еще один вопрос: как получить строковое представление для значений различного типа? К счастью, Python предоставляет возможность преобразовывать значение любого типа в строку: с помощью функции str(). Фактически язык предоставляет две функции для получения строкового представления - repr() (тот же эффект можно получить просто заключив выражение в обратные кавычки: `expr`) и str(). Первый способ, например, используется интерпретатором для вывода значений выражений в интерактивном режиме, второй - для вывода аргументов инструкцией print. Функция str() по возможности возвращает представление, наиболее пригодное для вывода, а функция repr() - для ввода выражения в интерактивном режиме. Приведем несколько примеров:

>>> x = 10 * 3.14

Число 31.4 не может быть точно представлено в двоичном виде, поэтому:

>>> x
31.399999999999999

Однако функция str() выведет число с разумной точностью:

>>> y = 200*200
>>> s = 'Значение x равно ' + str(x) + \
... ', значение y равно ' + str(y) + '...'
>>> print s
Значение x равно 31.4, значение y равно 40000...

Длинные целые числа записываются в языке Python с суффиксом 'L'. Начиная с версии 1.6, функция str() его не выводит:

>>> repr(1000L)
'1000L'
>>> str(1000L)
'1000'

Строковое представление можно получить и для других типов:

>>> p = [x, y]
>>> ps = repr(p)
>>> ps
'[31.399999999999999, 40000]'
>>> `x, y, ('spam', 'eggs')`
"(31.399999999999999, 40000, ('spam', 'eggs'))"

Функция repr() (или ``) добавляет кавычки и записывает спецсимволы с помощью управляющих последовательностей:

>>> hello = 'hello, world\n'
>>> print hello
hello, world
>>> hellos = `hello`
>>> print hellos
'hello, world\012'

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

>>> for x in range(1, 11):
... print str(x).rjust(2), str(x*x).rjust(3),
... # Обратите внимание на завершающую запятую
... print str(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 '%2d %3d %4d' % (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.)

Этот пример демонстрирует использование метода строк rjust(), который выравнивает строку вправо в поле заданной ширины, дополняя ее слева пробелами. Аналогично действуют методы ljust() и center(). Они не выводят ничего - просто возвращают новую строку. Если исходная строка слишком длинная, она не обрезается, а возвращается в неизменном виде: обычно лучше внести беспорядок в расположение колонок, чем вывести неверное значение. (Если Вы действительно хотите ее обрезать, воспользуйтесь операцией среза: 's.ljust(n)[0:n]'.)

Также может быть полезна функция zfill(), определенная в модуле string, которая дополняет слева нулями строку с числом, корректно обрабатывая знаки плюс и минус:

>>> import string
>>> string.zfill('12', 5)
'00012'
>>> string.zfill('-3.14', 7)
'-003.14'
>>> string.zfill('3.14159265359', 5)
'3.14159265359'

Использование оператора % выглядит примерно так:

>>> import math
>>> print 'Значение PI приближенно равно %5.3f.' % \
... math.pi
Значение PI приближенно равно 3.142.

Если в строке нужно вывести несколько значений, в качестве правого операнда используется кортеж:

>>> table = {'Sjoerd': 4127,
... 'Jack' : 4098,
... 'Dcab' : 7678}
>>> for name, phone in table.items():
... print '%-10s ==> %10d' % (name, phone)
...
Sjoerd ==> 4127
Dcab ==> 7678
Jack ==> 4098

Большинство форматов работают точно так же, как и в C. Однако, если типы аргументов не соответствуют формату, интерпретатор приводит их к необходимому типу (например, выражение любого типа может быть преобразовано в строку с помощью встроенной функции str()) или, если это невозможно, генерирует исключение [Из этого правила есть исключение: интерпретатор не будет преобразовывать строку к числовому типу.]. Вы можете использовать * для того, чтобы передать отдельным параметром ширину поля или точность.

Заметим, что если правый аргумент кортеж, он всегда считается списком аргументов:

>>> def f(x):
... print 'Функции передано значение "%s"' % x
...
>>> f(1)
Функции передано значение "1"
>>> f([1, 2])
Функции передано значение "[1, 2]"
>>> # интерпретируется не так, как Вы ожидали
... f((1,))
Функции передано значение "1"
>>> # ошибка
... f((1, 2))
Traceback (most recent call last): File "<stdin>", line 1, in ? File "<stdin>", line 2, in f
TypeError: not all arguments converted

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

>>> def f(x):
... print 'Функции передано значение "%s"' % (x,)
...
>>> # теперь все правильно
... f((1,))
Функции передано значение "(1,)"
>>> f((1, 2))
Функции передано значение "(1, 2)"

В случае длинных строк формата, Вы можете захотеть ссылаться на переменные по имени вместо их положения. Это можно сделать, используя расширенную запись в виде %(name)format, например:

>>> table = {'Sjoerd': 4127, 'Jack': 4098,
... 'Dcab': 8637678}
>>> print 'Jack: %(Jack)d; Sjoerd: %(Sjoerd)d; \
... Dcab: %(Dcab)d' % table
Jack: 4098; Sjoerd: 4127; Dcab: 8637678

Такая запись особенно полезна в комбинации со встроенной функцией vars(), которая возвращает словарь с переменными в текущей области видимости.

Более подробно операции над строками описаны в разделе 11.2.1.

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

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

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

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

В Windows (а в некоторых случаях и в Macintosh) файлы по умолчанию открываются в текстовом режиме - для того, чтобы открыть файл в двоичном режиме, необходимо к строке режима добавить 'b'. Следует помнить, что двоичные данные, такие как картинки в формате JPEG и даже текст в UNICODE, при чтении из файла или записи в файл, открытый в текстовом режиме, будут испорчены! Лучший способ оградить себя от неприятностей - всегда открывать файлы в двоичном режиме, даже на тех платформах, где двоичный режим используется по умолчанию (возможно у Вас когда-нибудь возникнет желание запустить программу на другой платформе).

Методы объектов-файлов

Примеры в этом разделе рассчитаны на то, что объект-файл f уже создан.

f.read(size) считывает и возвращает некоторое количество данных из файла. Аргумент size не является обязательным. Если он опущен или отрицательный, будет считано все содержимое файла, в противном случае, будет считано не более size байт данных. По достижении конца файла, возвращается пустая строка ().

>>> f.read() # Считываем все содержимое файла
'This is the entire file.\012'
>>> f.read()
''

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

>>> f.readline() # Считываем первую строку
'This is the first line of the file.\012'
>>> f.readline() # Считываем вторую строку
'Second line of the file\012'
>>> f.readline() # Достигли конца файла
''

f.readlines() считывает все содержимое файла, и возвращает список строк.

>>> f.readlines()
['This is the first line of the file.\012',
'Second line of the file\012']

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

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

f.tell() возвращает текущее положение в файле в байтах, отсчитываемое от начала файла. Чтобы изменить текущее положение, используйте 'f.seek(offset, from_what)'. Новое положение вычисляется путем добавления offset к точке отсчета. Точка отсчета выбирается в зависимости от значения аргумента from_what: 0 соответствует началу файла (используется по умолчанию, если метод вызывается с одним аргументом), 1 - текущему положению и 2 - концу файла.

>>> f=open('/tmp/workfile', 'rb+')
>>> f.write('0123456789abcdef')
>>> f.seek(5) # Go to the 5th byte in the file
>>> f.read(1)
'5'
>>> f.seek(-3, 2) # Go to the 3rd byte before the end
>>> f.read(1)
'd'

После того, как Вы закончили все операции с файлом, закройте файл с помощью f.close(). При попытке использовать закрытый файл для операций чтения/записи генерируется исключение ValueError:

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

Объекты-файлы имеют еще несколько методов, используемых не так часто (isatty(), truncate()). Для получения о них полной информации смотрите раздел 11.7.

Модуль pickle

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

Чтобы пользователю не приходилось постоянно писать и отлаживать код для сохранения сложных типов данных, Python предоставляет для этих целей стандартный модуль pickle. Этот изумительный модуль позволяет получить представление почти любого объекта (даже некоторые формы кода) в виде набора байтов (строки), одинакового для всех платформ. Такой процесс называют "консервированием" (pickling). Такое представление (законсервированный объект) можно сохранить в файле или передать через сетевое соединение на другую машину. К считанному из файла или принятому на другой машине законсервированному объекту может быть применена операция восстановления (unpickling).

Если у Вас есть объект x и файловый объект f, открытый для записи, простейший способ сохранить объект потребует всего одну строку кода:

pickle.dump(x, f)

Так же просто можно восстановить объект (f - файловый объект, открытый для чтения):

x = pickle.load(f)

Для получения полного представления о возможностях модуля pickle, смотрите его описание в третьей части книги.

Использование модуля pickle является стандартным в языке Python путем сохранения так называемых долгоживущих (persistent) объектов для дальнейшего использования. Модуль настолько часто используется, что многие авторы дополнительных модулей заботятся о том, чтобы новые типы данных (например, матрицы) могли быть правильно законсервированы.

Python   Теги:

Читать IT-новости в Telegram
Информационные технологии
Мы в соцсетях ✉