Главная страница

справочник по Python. мм isbn 9785932861578 9 785932 861578


Скачать 4.21 Mb.
Названиемм isbn 9785932861578 9 785932 861578
Анкорсправочник по Python
Дата08.05.2022
Размер4.21 Mb.
Формат файлаpdf
Имя файлаBizli_Python-Podrobnyy-spravochnik.440222.pdf
ТипСправочник
#518195
страница17 из 82
1   ...   13   14   15   16   17   18   19   20   ...   82
Глава
9
.
Ввод и вывод
В этой главе рассматриваются основы ввода-вывода данных на языке Py-
Py- thon, включая параметры командной строки, переменные окружения, файлы, поддержку Юникода и сериализацию объектов с помощью модуля pickle
Чтение параметров командной строки
При запуске программы на языке Python параметры командной строки со-
Python параметры командной строки со- параметры командной строки со- храняются в списке sys.argv. Первый элемент этого списка – имя програм- мы. Остальные элементы – это параметры, указанные в командной строке
после
имени программы. Ниже приводится пример прототипа программы, которая вручную обрабатывает простые параметры командной строки:
import sys if len(sys.argv) != 3:
sys.stderr.write(“Usage: python %s inputfile outputfile\n” % sys.argv[0])
raise SystemExit(1)
inputfile = sys.argv[1]
outputfile = sys.argv[2]
Элемент sys.argv[0] в этой программе содержит имя сценария, выполняемо- го в данный момент. Запись сообщения об ошибке в sys.stderr и возбужде- ние исключения SystemExit с ненулевым кодом завершения, как показано в примере, – это стандартный прием вывода сообщений об ошибках в ин- струментах командной строки.
В простых случаях параметры командной строки можно обрабатывать вручную, однако сложную обработку параметров командной строки лучше производить с помощью модуля optparse. Например:
import optparse p = optparse.OptionParser()
ёё
# Параметр имеет дополнительный аргумент p.add_option(“-o”,action=”store”,dest=”outfile”)

206
Глава 9. Ввод и вывод p.add_option(“--output”,action=”store”,dest=”outfile”)
ёё
# Параметр устанавливает логический флаг p.add_option(“-d”,action=”store_true”,dest=”debug”)
p.add_option(“--debug”,action=”store_true”,dest=”debug”)
ёё
# Установить значения по умолчанию для отдельных параметров p.set_defaults(debug=False)
ёё
# Анализ командной строки opts, args = p.parse_args()
ёё
# Извлечение значений параметров outfile = opts.outfile debugmode = opts.debug
В этом примере было добавлено два типа параметров. Первый параметр -o, или --output, принимает обязательный аргумент. Эта особенность опреде- ляется аргументом action=’store’ в вызове метода p.add_option(). Второй па- па- па- раметр -d, или --debug, просто устанавливает логический флаг. Это опре- просто устанавливает логический флаг. Это опре- устанавливает логический флаг. Это опре- устанавливает логический флаг. Это опре- логический флаг. Это опре- логический флаг. Это опре- флаг. Это опре- флаг. Это опре-
. Это опре-
Это опре- опре- опре- деляется аргументом action=’store_true’ в вызове p.add_option(). Аргумент dest в вызове p.add_option() определяет имя атрибута, в котором будет хра- ниться значение параметра после анализа. Метод p.set_defaults() устанав- ливает значения по умолчанию для одного или более параметров. Имена аргументов в вызове этого метода должны совпадать с именами атрибу- тов, в которых будут сохраняться значения параметров. Если значение по умолчанию не определено, атрибуты будут получать значение None.
Предыдущая программа правильно распознает все следующие параметры командной строки:
% python prog.py -o outfile -d infile1 ... infileN
% python prog.py --output=outfile --debug infile1 ... infileN
% python prog.py -h
% python prog.py --help
Анализ выполняется с помощью метода p.parse_args(). Этот метод возвра-
Этот метод возвра- щает кортеж из двух элементов (opts, args), где элемент opts – это объект, содержащий значения параметров, а args – это список элементов команд- ной строки, которые не были опознаны как допустимые параметры. Зна- чения параметров извлекаются из атрибутов opts.dest, где dest – это имя аргумента, указанного при добавлении параметра методом p.add_option().
Например, аргумент параметра -o или --output сохраняется в атрибуте opts.outfile
, тогда как args – это список остальных аргументов, такой как
[‘infile1’, ..., ‘infileN’]
. Модуль optparse автоматически добавляет пара- метр –h, или --help, в котором перечислены все допустимые параметры, ко- торые должны вводиться пользователем. Кроме того, передача недопусти- мых параметров приводит к выводу сообщения об ошибке.
Этот пример демонстрирует простейший случай использования модуля optparse
. Подробнее о некоторых дополнительных параметрах рассказыва- ется в главе 19 «Службы операционной системы».

Переменные окружения
207
Переменные окружения
Доступ к переменным окружения осуществляется с помощью словаря os.environ
. Например:
import os path = os.environ[“PATH”]
user = os.environ[“USER”]
editor = os.environ[“EDITOR”]
...
и т.д. ...
Чтобы изменить переменную окружения, достаточно присвоить значение элементу словаря os.environ. Например:
os.environ[“FOO”] = “BAR”
Изменения в словаре os.environ оказывают воздействие как на саму про- грамму, так и на все подпроцессы, созданные интерпретатором Python.
Файлы и объекты файлов
Встроенная функция open(name [,mode [,bufsize]]) открывает файл и создает объект файла, как показано ниже:
f = open(“foo”) # Откроет “foo” для чтения f = open(“foo”,’r’) # Откроет “foo” для чтения (как и выше)
f = open(“foo”,’w’) # Откроет “foo” для записи
Файл может быть открыт в режиме ‘r’ – для чтения, в режиме ‘w’ – для за- писи и в режиме ‘a’ – для добавления в конец. Эти режимы предполагают выполнение операций с текстовыми файлами и могут неявно производить преобразование символа перевода строки ‘\n’. Например, в Windows при записи символа ‘\n’ в действительности выводится последовательность из двух символов ‘\r\n’ (а при чтении последовательность ‘\r\n’ преобразу- ется обратно в одиночный символ ‘\n’). При работе с двоичными данными к символу режима открытия файла следует добавлять символ ‘b’, напри- мер: ‘rb’ или ‘wb’. Этот символ отключает преобразование символа перевода строки и обязательно должен указываться для обеспечения переносимости программного кода, обрабатывающего двоичные данные (программисты, работающие в UNIX, часто допускают ошибку, опуская символ ‘b’, из-за отсутствия различий между текстовыми и двоичными файлами). Кроме того, из-за имеющихся различий в режимах часто можно увидеть такое определение текстового режима, как ‘rt’, ‘wt’ или ‘at’, что более четко вы- ражает намерения программиста.
Файл может быть открыт в режиме обновления, за счет использования сим- вола (+), например: ‘r+’ или ‘w+’. Когда файл открыт в режиме для обновле- ния, допускается выполнять обе операции, чтения и записи, при условии, что все операции вывода будут выталкивать свои данные в файл до того, как будет выполнена операция ввода.
Если файл открывается в режиме ‘w+’, в момент открытия его длина усе- кается до нуля. Если файл открывается в режиме ‘U’ или ‘rU’, включается

208
Глава 9. Ввод и вывод поддержка универсального символа перевода строки для режима чтения.
Эта особенность упрощает обработку различных символов перевода строки
(таких как ‘\n’, ‘\r’ и ‘\r\n’), используемых на разных платформах, преоб- разуя их в стандартный символ ‘\n’ в строках, возвращаемых различными функциями ввода-вывода. Это может быть полезно, например, при разра- ботке сценариев для системы UNIX, которые должны обрабатывать тексто-
UNIX, которые должны обрабатывать тексто-
, которые должны обрабатывать тексто- вые файлы, созданные программами в Windows.
Необязательный аргумент bufsize управляет буферизацией файла, где зна- чение 0 означает отсутствие буферизации, значение 1 – построчную буфе- ризацию и отрицательное значение – буферизацию в соответствии с пара- метрами системы по умолчанию. Любое другое положительное число ин- терпретируется как примерный размер буфера в байтах.
В версии Python 3 в функцию open() было добавлено четыре дополнитель- ных аргумента – она вызывается как open(name [,mode [,bufsize [, encoding
[,
errors [, newline [, closefd]]]]]])
. Аргумент encoding определяет имя кодировки символов, например: ‘utf-8’ или ‘ascii’. Аргумент errors опреде- ляет политику обработки ошибок, связанных с кодировкой символов (до- полнительная информация о Юникоде приводится в следующих разделах этой главы). Аргумент newline определяет порядок работы в режиме под- держки универсального символа перевода строки и может принимать зна- чения None, ‘’, ‘\n’, ‘\r’ или ‘\r\n’. Если имеет значение None, любые символы окончания строки, такие как ‘\n’, ‘\r’ или ‘\r\n’, преобразуются в ‘\n’. Если имеет значение ‘’ (пустая строка), любые символы окончания строки рас- познаются, как символы перевода строки, но в исходном тексте остаются в первоначальном виде. Если аргумент newline имеет любое другое допу- стимое значение, оно будет использоваться для преобразования символов окончания строки. Аргумент closefd определяет, должен ли в действитель- ности закрываться дескриптор файла при вызове метода close(). По умол- умол- умол- чанию имеет значение True. В табл. 9.1 перечислены методы, поддерживае-
В табл. 9.1 перечислены методы, поддерживае- табл. 9.1 перечислены методы, поддерживае- табл. 9.1 перечислены методы, поддерживае-
. 9.1 перечислены методы, поддерживае- перечислены методы, поддерживае- мые объектами file.
Таблица 9.1. Методы файлов
Метод
Описание
f.read([n])
Читает из файла до n байтов.
f.readline([n])
Читает одну строку, но не более n байтов. Если аргу- мент n опущен, читает строку целиком.
f.readlines([size])
Читает все строки и возвращает список. С помощью необязательного аргумента size можно определить максимальное количество символов для чтения.
f.write(s)
Записывает строку s.
f.writelines(lines)
Записывает все строки из последовательности lines.
f.close()
Закрывает файл.
f.tell()
Возвращает текущую позицию в файле.
f.seek(offset [, whence])
Перемещает текущую позицию в новое место.

Файлы и объекты файлов
209
Метод
Описание
f.isatty()
Возвращает 1, если f представляет интерактивный терминал.
f.flush()
Выталкивает буферы вывода.
f.truncate([size])
Усекает размер файла до size байтов.
f.fileno()
Возвращает целочисленный дескриптор файла.
f.next()
Возвращает следующую строку или возбуждает исключение StopIteration. В Python 3 этот метод назы-
Python 3 этот метод назы- этот метод назы- вается f.__next__().
Метод read() возвращает содержимое файла целиком, в виде одной стро- ки, если не было указано значение необязательного аргумента, опреде- ляющее максимальное количество символов. Метод readline() возвраща- ет следующую строку из файла, включая завершающий символ перевода строки; метод readlines() возвращает все строки из файла в виде списка строк. Метод readline() принимает необязательный аргумент, определяю- щий максимальную длину строки, n. Если строка длиннее, чем значение n, возвращаются первые n символов. Оставшиеся символы не уничтожаются и будут возвращены следующими операциями чтения. Метод readlines() принимает аргумент size, определяющий примерное число символов, кото- рые должны быть прочитаны. Фактическое число прочитанных символов может оказаться больше этого значения, в зависимости от того, какой объ- ем данных был буферизован.
Оба метода, readline() и readlines(), учитывают особенности операционной системы и корректно обрабатывают различные представления окончания строки (например, ‘\n’ и ‘\r\n’). Если файл был открыт в режиме поддерж- ки универсального символа перевода строки (‘U’ или ‘rU’), символы оконча- ния строки преобразуются в ‘\n’.
Методы read() и readline() сообщают о достижении конца файла, возвра- щая пустую строку. В следующем фрагменте показано, как использовать эту особенность, чтобы определить достижение конца файла:
while True:
line = f.readline()
if not line: # Конец файла break
Файлы обеспечивают удобную возможность чтения всех строк в цикле for.
Например:
for line in f: # Итерации по всем строкам в файле
# Выполнить некоторые действия со строкой
...
Следует знать, что в Python 2 различные операции чтения всегда возвра-
Python 2 различные операции чтения всегда возвра-
2 различные операции чтения всегда возвра- щают 8-битные строки, независимо от выбранного режима доступа к фай- лу (текстовый или двоичный). В Python 3 эти операции возвращают стро-
Python 3 эти операции возвращают стро-
3 эти операции возвращают стро-

210
Глава 9. Ввод и вывод ки Юникода, если файл был открыт в текстовом режиме, и строки байтов – если файл был открыт в двоичном режиме.
Метод write() записывает в файл строку, а метод writelines() – список строк. Методы write() и writelines() не добавляют символы перевода стро- ки, поэтому выводимые строки должны включать все необходимые симво- лы форматирования. Эти методы могут записывать в файл простые строки байтов, но только если файл был открыт в двоичном режиме.
Каждый объект файла внутри хранит файловый указатель, то есть сме- щение от начала файла в байтах, откуда начнется следующая операция чтения или записи. Метод tell() возвращает текущее значение указателя в виде длинного целого числа. Метод seek() используется для организации произвольного доступа к различным частям файла, принимая значение
offset
смещения и флаг whence, определяющий, относительно какой пози- ции в файле будет откладываться указанное смещение. Если whence имеет значение 0 (по умолчанию), метод seek() отложит смещение offset от нача- ла файла; если whence имеет значение 1, смещение будет отложено относи- тельно текущей позиции в файле; а если whence имеет значение 2, смещение будет отложено от конца файла. Метод seek() возвращает новое значение файлового указателя в виде целого числа. Следует отметить, что файло- вый указатель связан с объектом файла, который возвращается функцией open()
, а не с самим файлом. Один и тот же файл можно открыть несколько раз в одной и той же программе (или в разных программах). При этом каж- дый экземпляр открытого файла будет иметь собственный, независимый от других, файловый указатель.
Метод fileno() возвращает целое число, представляющее дескриптор фай- ла, который иногда может использоваться в низкоуровневых операциях ввода-вывода, доступных в некоторых библиотечных модулях. Например, модуль fcntl использует файловые дескрипторы для выполнения низко- уровневых операций управления файлами в системах UNIX.
Кроме того, объекты файлов имеют атрибуты, доступные только для чте- ния, перечисленные в табл. 9.2.
Таблица 9.2. Атрибуты объектов файлов
Атрибут
Описание
f.closed
Логическое значение, соответствующее состоянию файла: False – файл открыт, True – закрыт.
f.mode
Режим ввода-вывода.
f.name
Имя файла, если он создан с помощью функции open(). В против- ном случае это будет строка с именем существующего файла.
f.softspace
Логическое значение, сообщающее, должна ли инструкция print выводить пробел перед очередным значением. Классы, имити- рующие файлы, должны предоставлять атрибут с этим именем, доступный для записи, инициализируемый нулем (только в Python 2).

Стандартный ввод, вывод и вывод сообщений об ошибках
211
Атрибут
Описание
f.newlines
Когда файл открывается в режиме поддержки универсального символа перевода строки, этот атрибут будет содержать пред- ставление символа окончания строки, фактически используемого в файле. Значением атрибута может быть None, которое говорит о том, что никаких символов завершения строки не было встрече- но; строка, содержащая ‘\n’, ‘\r’ или ‘\r\n’, или кортеж со всеми встреченными символами завершения строки.
f.encoding
Строка с названием кодировки файла, если определена (напри- мер, ‘latin-1’ или ‘utf-8’). Если кодировка не используется, этот атрибут имеет значение None.
Стандартный ввод, вывод
и вывод сообщений об ошибках
Интерпретатор предоставляет три стандартных объекта файлов, извест- ных, как стандартный ввод, стандартный вывод и стандартный вывод
сообщений об ошибках
, которые объявлены в модуле sys и доступны как sys.stdin
, sys.stdout и sys.stderr соответственно. stdin – это объект файла, соответствующий потоку входных символов, передаваемых интерпретато- ру. stdout – это объект файла, который принимает данные от инструкции print
. stderr – это объект файла, который принимает сообщения об ошиб- ках. Практически всегда объект stdin отображается на клавиатуру, а объ- екты stdout и stderr воспроизводят текст на экране.
Методы, описанные в предыдущем разделе, могут применяться пользова- телем для выполнения простых операций ввода-вывода. Например, следу- ющий фрагмент выводит данные на стандартный вывод и читает строку со стандартного ввода:
import sys sys.stdout.write(“Введите ваше имя: “)
name = sys.stdin.readline()
Дополнительно существует встроенная функция raw_input(prompt), которая читает строку текста из файла sys.stdin и может выводить приглашение к вводу:
name = raw_input(“Введите ваше имя : “)
Строки, возвращаемые функцией raw_input(), не включают завершающий символ перевода строки. Этим она отличается от простых операций чте- ния из файла sys.stdin, которые включают перевод строки в возвращаемый текст. В Python 3 функция raw_input() была переименована в input().
Ввод символа прерывания работы программы с клавиатуры (обычно гене- рируется комбинацией клавиш
Ctrl+C
) приводит к возбуждению исключе- ния KeyboardInterrupt, которое можно перехватить с помощью обработчика исключений.

212
Глава 9. Ввод и вывод
В случае необходимости значения переменных sys.stdout, sys.stdin и sys.
stderr могут замещаться другими объектами файлов, в этом случае ин- струкция print и функции ввода будут использовать новые значения. Если позднее потребуется восстановить оригинальное значение переменной sys.
stdout
, его предварительно следует сохранить. Кроме того, оригинальные значения переменных sys.stdout, sys.stdin и sys.stderr, которые присваива- ются при запуске интерпретатора, доступны в переменных sys.__stdout__, sys.__stdin__
и sys.__stderr__ соответственно.
Обратите внимание, что в некоторых случаях интегрированные среды раз- работки могут подменять значения переменных sys.stdin, sys.stdout и sys.
stderr
. Например, когда интерпретатор Python запускается под управлени-
Python запускается под управлени- запускается под управлени- ем IDLE, в переменную sys.stdin записывается ссылка на объект, который своим поведением напоминает файл, но в действительности является объ- ектом, созданным средой разработки. В этом случае некоторые низкоуров- невые методы, такие как read() и seek(), могут оказаться недоступными.
Инструкция print
Для вывода в файл, на который указывает переменная sys.stdout, в Py- в Py-
Py- thon 2 используется специальная инструкция print. Инструкция print при- нимает список объектов, разделенных запятыми, например:
print “Значения: “, x, y, z
Для каждого объекта вызывается функция str(), которая генерирует стро- ковое представление этого объекта. Затем эти строки объединяются в за- ключительную строку, где они разделяются символом пробела. Получен- ная строка завершается символом перевода строки, если в инструкции print отсутствует завершающая запятая. В противном случае следующая инструкция print добавит ведущий пробел перед выводом других объек- тов. Выводом этого пробела управляет атрибут softspace файла, в который производится вывод.
print “Значения: “, x, y, z, w
# Вывести тот же текст с помощью двух инструкций print print “Значения: “, x, y, # Завершающий символ перевода строки не выводится print z, w # Перед значением z будет выведен пробел
Для вывода форматированных строк используется оператор форматирова- ния (%) или метод .format(), как было описано в главе 4 «Операторы и вы- ражения». Например:
print “Значения: %d %7.5f %s” % (x,y,z) # Форматированный ввод-вывод print “Значения: {0:d} {1:7.5f} {2}”.format(x,y,z)
Файл, куда производится вывод инструкцией print, можно заменить, до- бавив специальный модификатор >>file, со следующей за ним запятой, где
file
– это объект файла, открытый в режиме для записи. Например:
f = open(“output”,”w”)
print >>f, “привет, мир”
...
f.close()

Функция print()
213
Функция print()
Одним из самых существенных изменений в Python 3 является преобра-
Python 3 является преобра-
3 является преобра- зование инструкции print в функцию. В Python 2.6 инструкция print мо- жет вызываться, как функция, если добавить инструкцию from __future__ import print_function в каждый модуль, который ее использует. Функция print()
действует практически так же, как и инструкция print, описанная в предыдущем разделе.
Чтобы вывести несколько значений, достаточно просто перечислить их че- рез запятую в списке аргументов print(), например:
print(“Значения: “, x, y, z)
Подавить или изменить символ окончания строки можно с помощью име- нованного аргумента end=ending. Например:
print(“Значения: “, x, y, z, end=’’) # Подавит вывод конца строки
Перенаправить вывод в файл можно с помощью именованного аргумента file=
outfile
. Например:
print(“Значения: “, x, y, z, file=f) # Произведет вывод в объект файла f
Изменить символ-разделитель между элементами можно с помощью име- нованного аргумента sep=sepchr. Например:
print(“Значения: “, x, y, z, sep=’,’) # Выведет запятую между значениями
Интерполяция переменных при выводе текста
Типичная проблема, возникающая при выводе, связана с вводом больших фрагментов текста, содержащих переменные. Во многих языках сценари- ев, таких как Perl и PHP, имеется возможность вставлять имена перемен-
Perl и PHP, имеется возможность вставлять имена перемен- и PHP, имеется возможность вставлять имена перемен-
PHP, имеется возможность вставлять имена перемен-
, имеется возможность вставлять имена перемен- ных в строки, используя оператор ($) подстановки значений переменных (то есть $name, $address и так далее). В языке Python отсутствует прямой экви-
Python отсутствует прямой экви- отсутствует прямой экви- валент этой возможности, но ее можно имитировать, используя операцию форматирования строк в соединении со строками в тройных кавычках.
Например, можно было бы создать шаблон письма, в котором присутству- ют переменные элементы name, item и amount, как показано ниже:
# Обратите внимание: завершающий символ обратного слэша, сразу за “””
# подавляет вывод первой пустой строки form = “””\
Уважаемый %(name)s,
Пожалуйста, верните обратно %(item)s или заплатите $%(amount)0.2f.
Искренне ваш,
ёё
Joe Python User
“””
print form % { ‘name’: ‘Мистер Буш’,
‘item’: ‘блендер’,
‘amount’: 50.00,
}

214
Глава 9. Ввод и вывод
В результате будет получен следующий вывод:
Уважаемый Мистер Буш,
ёё
Пожалуйста, верните обратно блендер или заплатите $50.00.
ёё
Искренне ваш,
Joe Python User
Метод format() является более современной альтернативой, позволяя сде- лать предыдущий программный код более наглядным. Например:
form = “””\
Уважаемый {name},
Пожалуйста, верните обратно {item} или заплатите {amount:0.2f}.
Искренне ваш,
ёё
Joe Python User
“””
print form.format(name=’Мистер Буш’, item=’блендер’, amount=50.0)
В некоторых случаях можно также использовать метод Template() из моду- ля string, как показано ниже:
import string form = string.Template(“””\
Уважаемый $name,
Пожалуйста, верните обратно $item или заплатите $amount.
Искренне ваш,
ёё
Joe Python User
“””)
print form.substitute({‘name’: ‘Мистер Буш’,
‘item’: ‘блендер’,
‘amount’: “%0.2f” % 50.0})
В данном случае специальные переменные, начинающиеся с символа $, в строке являются символами подстановки. Метод form.substitute() при- нимает словарь подставляемых значений и возвращает новую строку. Не- смотря на простоту предыдущего примера, этот подход не всегда являет- ся достаточно мощным решением при создании текста. Веб-фреймворки, как и многие другие фреймворки разработки приложений, обычно предо- ставляют свои собственные механизмы шаблонов, которые поддержива- ют встроенные операторы управления потоком выполнения, подстановки переменных, включения файлов и другие расширенные особенности.
Вывод с помощью генераторов
Непосредственная работа с файлами – это самая знакомая программистам модель ввода-вывода. Однако для вывода последовательности фрагментов данных также могут использоваться функции-генераторы. Для этого до- статочно просто задействовать инструкцию yield вместо метода write() или инструкции print. Например:

Обработка строк Юникода
215
def countdown(n):
while n > 0:
yield “Очередное значение %d\n” % n n -= 1
yield “Конец!\n”
Создание потоков выходных данных таким способом обеспечивает значи- тельную гибкость, потому что создание выходного потока отделено от про- граммного кода, который фактически направляет поток адресату. Напри- мер, при желании вывод можно направить в файл f, как показано ниже:
count = countdown(5)
f.writelines(count)
Точно так же можно направить данные в сокет s, например:
for chunk in count:
s.sendall(chunk)
Или просто записать данные в строку:
out = “”.join(count)
Более сложные приложения могут использовать такой подход, реализовав свой собственный механизм буферизации ввода-вывода. Например, гене- ратор мог бы производить небольшие фрагменты текста, а другая функция могла бы собирать эти фрагменты в большие буферы, повышая тем самым эффективность операций ввода-вывода:
chunks = []
buffered_size = 0
for chunk in count:
chunks.append(chunk)
buffered_size += len(chunk)
if buffered_size >= MAXBUFFERSIZE:
outf.write(“”.join(chunks))
chunks.clear()
buffered_size = 0
outf.write(“”.join(chunks)
Для программ, направляющих вывод в файлы или в сетевые соединения, подход на основе генераторов может также способствовать существенному снижению требований к объему памяти, потому что весь выходной поток зачастую может генерироваться и обрабатываться небольшими фрагмента- ми, в противоположность методу, когда сначала данные собираются в одну большую строку или список строк. Такой способ вывода данных иногда можно встретить в программах на языке Python, взаимодействующих со шлюзовым интерфейсом веб-служб (Web Services Gateway Interface –
WSGI), который используется для обмена информацией между программ-
), который используется для обмена информацией между программ- ными компонентами в некоторых веб-фреймворках.
Обработка строк Юникода
Типичной проблемой, связанной с вводом-выводом, является обработка ин тернациональных символов, представленных символами Юникода.

216
Глава 9. Ввод и вывод
Е
сли имеется некоторая строка s, состоящая из байтов, которые являют- ся кодированным представлением символов Юникода, для ее преобразо- вания в соответствующую строку Юникода можно использовать метод
s.decode([encoding [,errors]])
. Преобразовать строку Юникода u в кодирован- ную строку байтов можно с помощью строкового метода u.encode([encoding
[,
errors]])
. Оба эти метода, выполняющие преобразование, принимают специальное имя кодировки, определяющей порядок отображения симво- лов Юникода в последовательности 8-битных символов и наоборот. Аргу- мент encoding определяется как строка и может быть именем одной из более чем сотни различных названий кодировок. Ниже приводятся наиболее ча- сто встречаемые значения:
Значение
Описание
‘ascii’
7-битная кодировка ASCII
‘latin-1’ или ‘iso-8859-1’
ISO 8859-1 Latin-1
‘cp1252’
Кодировка Windows 1252
‘utf-8’
8-битная кодировка с символами переменной длины
‘utf-16’
16-битная кодировка с символами переменной дли- ны (может быть с прямым и с обратным порядком следования байтов)
‘utf-16-le’
UTF-16, кодировка с обратным порядком (little en-
-16, кодировка с обратным порядком (little en- little en- en- en- dian) следования байтов
‘utf-16-be’
UTF-16, кодировка с прямым порядком (big endian) следования байтов
‘unicode-escape’
Формат литералов строк Юникода u”string”
‘raw-unicode-escape’
Формат литералов «сырых» строк Юникода ur”string”
Кодировку по умолчанию, которая устанавливается модулем site, можно получить с помощью функции sys.getdefaultencoding(). Во многих случаях по умолчанию используется кодировка ‘ascii’, которая напрямую отобра- жает символы ASCII с кодами в диапазоне [0x00,0x7f] в символы Юникода в диапазоне [U+0000, U+007F]. Однако кодировка ‘utf-8’ также используется достаточно часто. Технические подробности, касающиеся наиболее распро- страненных кодировок, приводятся в следующем разделе.
Когда используется метод s.decode(), всегда предполагается, что s – это строка байтов. В Python 2 s интерпретируется, как стандартная строка, но в Python 3 строка s должна быть объектом специального типа bytes.
Аналогично результатом вызова метода t.encode() всегда является после- довательность байтов. Если вас волнует проблема переносимости, замечу, что в Python 2 эти методы могут стать источником путаницы. Например, строки в Python 2 обладают обоими методами, decode() и encode(), тогда как в Python 3 строки имеют только метод encode(), а тип bytes – только метод

Обработка строк Юникода
217
decode()
. Чтобы упростить последующий перенос программного кода для
Python 2, используйте метод encode() только со строками Юникода, а метод decode()
– только со строками байтов.
Если при преобразовании строковых значений встретится символ, кото- рый не может быть преобразован в требуемую кодировку, будет возбуж- дено исключение UnicodeError. Например, если попытаться преобразовать в кодировку ‘ascii’ строку, содержащую символы Юникода, такие как
U+1F28
, возникнет ошибка кодирования, так как значение этого символа окажется слишком большим для представления в наборе символов ASCII.
Аргумент errors методов encode() и decode() определяет порядок обработки ошибок, возникающих при преобразовании. Это должна быть строка с од- ним из следующих значений:
Значение
Описание
‘strict’
В случае появления ошибки кодирования и декодиро- вания возбуждается исключение UnicodeError.
‘ignore’
Недопустимые символы игнорируются.
‘replace’
Замещает недопустимые символы символом замены
(U+FFFD – в строках Юникода,
‘?’
– в стандартных строках).
‘backslashreplace’
Замещает недопустимые символы соответствующими им экранированными последовательностями, приня- тыми в языке Python. Например, символ U+1234 будет замещен последовательностью ‘\u1234’.
‘xmlcharrefreplace’
Замещает недопустимые символы ссылками в форма- недопустимые символы ссылками в форма- недопустимые символы ссылками в форма- символы ссылками в форма- символы ссылками в форма- ссылками в форма- ссылками в форма- в форма- в форма- форма- форма- те XML. Например, символ U+1234 будет замещен по- следовательностью ‘ሴ’.
По умолчанию используется значение ‘strict’.
Политика обработки ошибок ‘xmlcharrefreplace’ часто является удобным способом встраивания интернациональных символов в текст ASCII веб- страниц. Например, если вывести строку Юникода ‘Jalape\u00f1o’, закоди- ровав ее в кодировку ASCII с политикой обработки ошибок ‘xmlcharrefre- xmlcharrefre- place’
, броузеры практически всегда корректно отобразят текст строки как
“Jalapeсo”, а не как немного искаженную альтернативу.
Чтобы избавить себя от лишней головной боли, никогда не смешивайте в выражениях кодированные строки байтов и декодированные строки (на- пример, в операции + конкатенации). В Python 3 это вообще невозможно, но в Python 2 такие операции будут выполняться без вывода каких-либо сообщений об ошибках, автоматически преобразуя строки байтов в строки
Юникода, используя значение кодировки по умолчанию. Такое поведение часто приводит к неожиданным результатам или непонятным сообщениям об ошибках. Поэтому в программах всегда следует строго отделять кодиро- ванные и некодированные символьные данные.

218
Глава 9. Ввод и вывод
Ввод-вывод Юникода
При работе со строками Юникода нет никакой возможности напрямую за- писать данные в файл. Это обусловлено тем, что во внутреннем представле- нии символы Юникода являются многобайтовыми целыми числами и при непосредственной записи таких чисел в поток вывода возникают пробле- мы, связанные с порядком следования байтов. Например, вам пришлось бы решить, записывать ли символ Юникода U+HHLL в формате с «обратным порядком следования байтов», как LL HH, или в формате с «прямым поряд- ком следования байтов», как HH LL. Кроме того, другие инструменты, вы- полняющие обработку текста Юникода, должны знать, какая кодировка была использована при записи.
Из-за этой проблемы преобразование строк Юникода во внешнее представ- ление всегда выполняется в соответствии с определенными правилами кодирования, которые четко определяют, как преобразовывать символы
Юникода в последовательности байтов. По этой причине, чтобы обеспечить поддержку ввода-вывода Юникода, понятия кодирования и декодирова- ния, описанные в предыдущем разделе, были распространены на файлы.
Встроенный модуль codecs содержит набор функций, позволяющих выпол- нять преобразование байтовых данных в строки Юникода и обратно, в со- ответствии с различными схемами кодирования.
Самый прямолинейный, пожалуй, способ обработки файлов Юникода за- ключается в использовании функции codecs.open(filename [, mode [, encod-
ing [, errors]]])
, как показано ниже:
f = codecs.open(‘foo.txt’,’r’,’utf-8’,’strict’) # Чтение g = codecs.open(‘bar.txt’,’w’,’utf-8’) # Запись
Здесь создаются объекты файлов, из одного производится чтение строки
Юникода, в другой – запись. Аргумент encoding определяет способ коди- рования символов, который будет использоваться при чтении и записи данных. Аргумент errors определяет политику обработки ошибок и может принимать одно из значений: ‘strict’, ‘ignore’, ‘replace’, ‘backslashreplace’ или ‘xmlcharrefreplace’, как было описано в предыдущем разделе.
Если в программе уже имеется объект файла, то функцию codecs.
EncodedFile(
file, inputenc [, outputenc [, errors]])
можно использовать в качестве обертки вокруг этого объекта, выполняющей кодирование. На- пример:
f = open(“foo.txt”,”rb”)
...
fenc = codecs.EncodedFile(f,’utf-8’)
В данном примере интерпретация данных, читаемых из файла, будет вы- полняться в соответствии с кодировкой, указанной в аргументе inputenc, а при записи – в соответствии с кодировкой в аргументе outputenc. Если аргумент outputenc опущен, по умолчанию будет использоваться значение аргумента inputenc. Аргумент errors имеет то же назначение, как было опи- сано выше. При использовании обертки EncodedFile вокруг существующего объекта файла файл должен быть открыт в двоичном режиме. В противном

Ввод-вывод Юникода
219
случае преобразование символов перевода строки может препятствовать кодированию.
При работе с файлами Юникода помните, что информация об используемой кодировке может включаться в сам файл. Например, парсеры разметки
XML могут определить кодировку документа, просматривая первые не- могут определить кодировку документа, просматривая первые не- сколько байтов строки ‘’. Если первые четыре байта в этой стро- ке –3C 3F 78 6D (‘UTF-8. Если первые четыре байта – 00 3C 00 3F или 3C 00 3F 00, можно пред- положить, что используется кодировка UTF-16 с прямым порядком следо-
UTF-16 с прямым порядком следо-
-16 с прямым порядком следо- вания байтов или UTF-16 с обратным порядком следования байтов соответ-
UTF-16 с обратным порядком следования байтов соответ-
-16 с обратным порядком следования байтов соответ- ственно. Кроме того, кодировка документа может указываться в заголовках
MIME или в виде других атрибутов элементов документа. Например:
... encoding=”ISO-8859-1” ... ?>
Аналогично файлы Юникода также могут включать специальные марке- ры порядка следования байтов (Byte-Order Markers – BOM), указывающие на свойства кодировки символов. Для этих целей зарезервирован символ
Юникода U+FEFF. Обычно маркер записывается как первый символ в фай-
Обычно маркер записывается как первый символ в фай- ле. Программы, прочитав этот символ, могут по следующим за ним байтам определить используемую кодировку (например, ‘\xff\xfe’ – для UTF-16-
LE или ‘\xfe\xff’ – для UTF-16-BE). После определения кодировки символ
BOM отбрасывается и обрабатывается остальная часть файла. К сожале- отбрасывается и обрабатывается остальная часть файла. К сожале- нию, все эти дополнительные манипуляции с маркерами BOM не выпол-
BOM не выпол- не выпол- няются внутренней реализацией. Чаще всего вам придется самим поза- ботиться об этом, если приложение должно гарантировать такую возмож- ность.
Когда кодировка определяется подобным способом, по первым байтам в до- кументе, можно использовать следующий ниже программный код, превра- щающий входной файл в поток кодированных данных:
f = open(“somefile”,”rb”)
# Определить кодировку данных
...
# Обернуть объект файла, указав требуемую кодировку.
# Далее предполагается, что символ BOM (если таковой имеется)
# уже был отброшен предыдущими инструкциями.
fenc = codecs.EncodedFile(f,encoding)
data = fenc.read()
Кодировки данных Юникода
В табл. 9.3 перечислены кодировки в модуле codecs, используемые наибо- лее часто.
Таблица 9.3. Кодировки, реализованные в модуле codecs
Кодировка
Описание
‘ascii’
Кодировка ASCII
‘latin-1’ или ‘iso-8859-1’
Кодировка Latin-1 или ISO 8859-1

220
Глава 9. Ввод и вывод
‘cp437’
Кодировка CP437
‘cp1252’
Кодировка CP1252
‘utf-8’
8-битная кодировка с символами переменной длины
‘utf-16’
16-битная кодировка с символами переменной длины
‘utf-16-le’
Кодировка UTF-16, но с явно указанным обратным порядком (little endian) следования байтов
‘utf-16-be’
Кодировка UTF-16, но с явно указанным прямым по-
UTF-16, но с явно указанным прямым по-
-16, но с явно указанным прямым по- рядком (big endian) следования байтов
‘unicode-escape’
Формат литералов строк Юникода u”string
‘raw-unicode-escape’
Формат литералов «сырых» строк Юникода ur”
string
В следующих разделах приводятся более подробные описания каждой из кодировок.
Кодировка ‘ascii’
В кодировке ‘ascii’ значения символов ограничены диапазонами [0x00,0x7f] и [U+0000, U+007F]. Любые символы, со значениями за пределами этих диа- пазонов, считаются недопустимыми.
Кодировка ‘iso-8859-1’, ‘latin-1’
Символы могут иметь любые 8-битные значения в диапазонах [0x00,0xff] и [U+0000, U+00FF]. Символы со значениями в диапазоне [0x00,0x7f] соответ- ствуют символам ASCII. Символы со значениями в диапазоне [0x80,0xff] соответствуют символам в кодировке ISO-8859-1, или расширенному набо-
ISO-8859-1, или расширенному набо-
-8859-1, или расширенному набо- ру символов ASCII. Любые символы со значениями за пределами диапазо-
ASCII. Любые символы со значениями за пределами диапазо-
. Любые символы со значениями за пределами диапазо- на [0x00,0xff] вызывают появление ошибки.
Кодировка ‘cp437’
Эта кодировка похожа на кодировку ‘iso-8859-1’ и используется интерпре- татором Python по умолчанию, когда программа запускается в Windows как консольное приложение. Некоторые символы, со значениями в диа- пазоне [x80,0xff], интерпретируются как специальные символы, исполь- зуемые при отображении меню, окон и рамок в устаревших программах, написанных для DOS.
Кодировка ‘cp1252’
Эта кодировка очень похожа на кодировку ‘iso-8859-1’ и используется в Windows. Однако эта кодировка определяет символы в диапазоне [0x80-
0x9f]
, которые не определены в кодировке ‘iso-8859-1’ и имеют другие кодо- вые пункты в Юникоде.
Таблица 9.3 (продолжение)

Ввод-вывод Юникода
221
Кодировка ‘utf-8’
UTF
-8 – это кодировка, в которой символы могут иметь переменную длину, что позволяет представлять все символы Юникода. Символы ASCII в этой кодировке представлены единственным байтом, со значением в диапазоне
0–127. Все остальные символы представлены последовательностями бай- тов длиной от 2 до 3 байтов. Порядок кодирования этих байтов приводится ниже:
Символ Юникода
Байт 0
Байт 1
Байт 2
U+0000 - U+007F
0
nnnnnnn
U+007F - U+07FF
110
nnnnn
10
nnnnnn
U+0800 - U+FFFF
1110
nnnn
10
nnnnnn
10
nnnnnn
Первый байт в 2-байтовых последовательностях всегда начинается с после- довательности битов 110. В 3-байтовых последовательностях первый байт начинается с последовательности битов 1110. Все последующие байты дан- ных в многобайтовых последовательностях начинаются с последователь- ности битов 10.
Вообще говоря, кодировка UTF-8 позволяет использовать многобайтовые последовательности длиной до 6 байтов. Для кодирования пар символов
Юникода в Python используются 4-байтовые последовательности UTF-8, которые называются суррогатными парами. Оба символа в таких парах имеют значения в диапазоне [U+D800, U+DFFF] и при объединении состав- ляют 20-битный код символа. Суррогатное кодирование выполняется сле- дующим образом: 4-байтовая последовательность 11110nnn 10nnnnnn 10nmmmm
10
mmmmm
кодируется как пара U+D800 + N, U+DC00 + M, где N – это старшие 10 би- тов, а M – младшие 10 битов 20-битового символа, представленного в виде
4-байтовой последовательности UTF-8. Пяти- и шестибайтовые последова-
UTF-8. Пяти- и шестибайтовые последова-
-8. Пяти- и шестибайтовые последова- тельности UTF-8 (в первом байте обозначаются последовательностями би-
UTF-8 (в первом байте обозначаются последовательностями би-
-8 (в первом байте обозначаются последовательностями би- тов 111110 и 1111110 соответственно) используются для кодирования симво- лов с 32-битными значениями. Эти значения не поддерживаются в языке
Python и в настоящее время, если они появляются в потоке данных, вы- и в настоящее время, если они появляются в потоке данных, вы- зывают исключение UnicodeError.
Кодировка UTF-8 имеет множество полезных свойств, позволяющих ис-
UTF-8 имеет множество полезных свойств, позволяющих ис-
-8 имеет множество полезных свойств, позволяющих ис- пользовать эту кодировку в устаревших приложениях. Во-первых, стан- дартные символы ASCII представлены в ней своими собственными кодами.
Это означает, что строки символов ASCII в кодировке UTF-8 ничем не отли-
ASCII в кодировке UTF-8 ничем не отли- в кодировке UTF-8 ничем не отли-
UTF-8 ничем не отли-
-8 ничем не отли- чаются от традиционных строк ASCII. Во-вторых, кодировка UTF-8 не ис-
ASCII. Во-вторых, кодировка UTF-8 не ис-
. Во-вторых, кодировка UTF-8 не ис-
UTF-8 не ис-
-8 не ис- пользует байты со значением NULL в многобайтовых последовательностях.
Благодаря этому существующие программы, опирающиеся на использо- вание библиотеки языка C, и программы, в которых используются 8-бит-
C, и программы, в которых используются 8-бит-
, и программы, в которых используются 8-бит- ные строки, оканчивающиеся символом NULL, смогут работать со строками
UTF-8. Наконец, кодировка UTF-8 сохраняет возможность лексикографи-
-8. Наконец, кодировка UTF-8 сохраняет возможность лексикографи-
UTF-8 сохраняет возможность лексикографи-
-8 сохраняет возможность лексикографи- ческого упорядочивания строк. То есть, если имеются строки Юникода a и b, где a < b, то после преобразования строк в кодировку UTF-8 условие

222
Глава 9. Ввод и вывод a < b также будет выполняться. Поэтому алгоритмы сортировки и упорядо- чения, написанные для 8-битных строк, также будут работать со строками в кодировке UTF-8.
Кодировки ‘utf-16’, ‘utf-16-be’ и ‘utf-16-le’
UTF-16 – это 16-битная кодировка, в которой символы Юникода перемен-
-16 – это 16-битная кодировка, в которой символы Юникода перемен- ной длины записываются 16-битными значениями. Если порядок следо- вания байтов не указан, предполагается кодирование с прямым порядком следования байтов (big endian). Кроме того, для явного указания порядка следования байтов в потоке данных UTF-16 может использоваться маркер
U+FEFF
. В кодировке с прямым порядком следования байтов значение U+FEFF представляет символ Юникода неразрывного пробела нулевой ширины, тогда как значение с переставленными байтами, U+FFFE, является недопу- стимым символом Юникода. Благодаря этому последовательности байтов
FE FF
или FF FE могут использоваться для определения порядка следова- ния байтов в потоке данных. При чтении данных Юникода Python удаляет маркеры порядка следования байтов из окончательной строки Юникода.
Кодировка ‘utf-16-be’ явно определяет кодировку UTF-16 с прямым поряд-
UTF-16 с прямым поряд-
-16 с прямым поряд- ком следования байтов (big endian).
Кодировка ‘utf-16-le’ явно определяет кодировку UTF-16 с обратным по-
UTF-16 с обратным по-
-16 с обратным по- рядком следования байтов (little endian).
Кодировка UTF-16 имеет расширения, обеспечивающие возможность под-
UTF-16 имеет расширения, обеспечивающие возможность под-
-16 имеет расширения, обеспечивающие возможность под- держки символов со значениями больше 16 битов, однако в настоящее вре- мя ни одно из этих расширений не поддерживается.
Кодировки ‘unicode-escape’ и ‘raw-unicode-escape’
Эти кодировки используются для преобразования строк Юникода в фор- мат, который используется в языке Python для представления литералов строк Юникода и литералов «сырых» строк Юникода. Например:
s = u’\u14a8\u0345\u2a34’
t = s.encode(‘unicode-escape’) # t = ‘\u14a8\u0345\u2a34’
Свойства символов Юникода
В дополнение к операциям ввода-вывода в программах, где используется
Юникод, может потребоваться проверить различные свойства символов
Юникода, такие как регистр символа, принадлежность к цифрам и про- бельным символам. Доступ к базе данных свойств символов Юникода обе- спечивает модуль unicodedata. Вообще говоря, свойства символов можно получить вызовом функции unicodedata.category(c). Например, вызов uni- codedata.category(u”A”)
вернет результат ‘Lu’, который говорит, что символ является заглавной буквой.
Еще одна проблема заключается в том, что одна и та же строка Юникода может иметь несколько представлений. Например, символ U+00F1 (
ñ) мо- жет быть представлен единственным символом U+00F1 или многосимволь- ной последовательностью U+006e U+0303 (n,
˜). Если единообразие обработки

Сохранение объектов и модуль pickle
223
строк Юникода имеет важное значение, единство представления символов можно обеспечить с помощью функции unicodedata.normalize(). Например, вызов unicodedata.normalize(‘NFC’, s) гарантирует, что все символы в строке
s
будут скомпонованы и ни один из них не будет представлен последова- тельностью комбинируемых символов.
Подробнее о базе данных символов Юникода и о модуле unicodedata расска- зывается в главе 16 «Строки и обработка текста».
Сохранение объектов и модуль pickle
Очень часто бывает необходимо сохранить содержимое объекта в файле и восстановить его из файла. Чтобы решить эту проблему, можно написать пару функций, которые будут просто читать из файла и записывать дан- ные в файл в специальном формате. Альтернативное решение заключается в использовании модулей pickle и shelve.
Модуль pickle преобразует объект в последовательность байтов, которая может быть записана в файл, а потом прочитана из файла. Интерфейс мо- дуля pickle прост, он состоит из функций dump() и load(). Например, следую- щий фрагмент демонстрирует возможность записи объекта в файл:
import pickle obj = SomeObject()
f = open(filename,’wb’)
pickle.dump(obj, f) # Сохранит объект в f f.close()
Следующий фрагмент восстанавливает объект:
import pickle f = open(filename,’rb’)
obj = pickle.load(f) # Восстановит объект f.close()
Последовательность объектов можно сохранить серией вызовов функции dump()
, один за другим. Восстановить эти объекты можно аналогичной се- эти объекты можно аналогичной се- эти объекты можно аналогичной се- объекты можно аналогичной се- объекты можно аналогичной се- можно аналогичной се- можно аналогичной се- аналогичной се- аналогичной се- се- се- рией вызовов функции load().
Модуль shelve похож на модуль pickle, но сохраняет объекты в базе данных, своей структурой напоминающей словарь:
import shelve obj = SomeObject()
db = shelve.open(“filename”) # Открыть хранилище db[‘key’] = obj # Сохранить объект в хранилище
...
obj = db[‘key’] # Извлечь объект db.close() # Закрыть хранилище
Хотя объект, создаваемый модулем shelve, выглядит как словарь, тем не ме- нее он имеет некоторые ограничения. Во-первых, ключи могут быть только строками. Во-вторых, значения, сохраняемые в хранилище, должны быть совместимы с требованиями модуля pickle. Этим требованиям отвечает

224
Глава 9. Ввод и вывод большинство объектов Python, однако некоторые объекты специального назначения, такие как файлы и сетевые соединения, хранящие информа- цию о внутреннем состоянии, не могут быть сохранены и восстановлены таким способом.
Формат данных, который используется модулем pickle, характерен для языка Python. Однако этот формат несколько раз изменялся с выходом новых версий Python. Выбор протокола
1 может быть осуществлен с помо- щью дополнительного аргумента protocol функции dump(obj, file, protocol) в модуле pickle. По умолчанию используется протокол 0. Это самый старый формат представления данных модулем pickle, который может восприни- маться практически всеми версиями Python. Однако этот формат несовме- стим со многими современными особенностями классов в языке Python, такими как слоты. В протоколах 1 и 2 используется более эффективное представление двоичных данных. Чтобы использовать эти альтернативные протоколы, необходимо выполнить такие операции, как:
import pickle obj = SomeObject()
f = open(filename,’wb’)
pickle.dump(obj,f,2) # Использовать протокол 2
pickle.dump(obj,f,pickle.HIGHEST_PROTOCOL) # Использовать самый современный
# протокол f.close()
При восстановлении объектов с помощью функции load() указывать прото- кол не требуется, так как номер протокола записывается непосредственно в файл.
Аналогично модуль shelve может создавать хранилища для сохранения объектов Python с использованием альтернативного протокола модуля pickle
, например:
import shelve db = shelve.open(filename,protocol=2)
...
При работе с пользовательскими объектами обычно не требуется выпол- нять дополнительные операции с привлечением модуля pickle или shelve.
Однако объекты могут определять дополнительные методы __getstate__() и __setstate__() для оказания помощи процессу сохранения и восстанов- ления. Метод __getstate__(), если он определен, вызывается для создания значения, являющегося представлением состояния объекта. Значение, возвращаемое методом __getstate__(), может быть строкой, кортежем, спи- ском или словарем. Метод __setstate__() принимает это значение в про- цессе чтения объекта из файла и должен восстанавливать его состояние, исходя из этого значения. Ниже приводится пример, демонстрирующий реализации этих методов в объекте, который создает сетевое подключение.
Несмотря на то что фактическое подключение нельзя сохранить в файле,
1
Имеется в виду выбор номера версии формата. – Прим. перев.

Сохранение объектов и модуль pickle
225
в объекте имеется достаточный объем информации, чтобы возобновить это подключение после того, как объект будет восстановлен из файла:
import socket class Client(object):
def __init__(self,addr):
self.server_addr = addr self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.connect(addr)
def __getstate__(self):
return self.server_addr def __setstate__(self,value):
self.server_addr = value self.sock = socket.socket(socket.AF_INET,socket.SOCK_STREAM)
self.sock.connect(self.server_addr)
Поскольку модуль pickle использует формат, характерный только для языка Python, эту возможность нельзя использовать для обмена данными между приложениями, написанными на других языках программирова- ния. Кроме того, из-за проблем безопасности программы не должны обра- батывать сохраненные данные, полученные из непроверенных источников
(опытный злоумышленник сможет подделать файл с данными так, чтобы обеспечить выполнение любых системных команд в процессе его чтения).
Модули pickle и shelve имеют множество параметров настройки и спосо- бов использования. Более подробные сведения о них приводятся в главе 13
«Службы Python времени выполнения».

1   ...   13   14   15   16   17   18   19   20   ...   82


написать администратору сайта