справочник по Python. мм isbn 9785932861578 9 785932 861578
Скачать 4.21 Mb.
|
Глава 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 времени выполнения». |