Марк Лутц - Изучаем Python, Четвертое издание (1184811), страница 76
Текст из файла (страница 76)
И иногда даже слишком мощный. Функция eval без лишних вопросов выполнит любое выражениена языке Python, даже если в результате будут удалены все файлы в компьютере, если передать в выражение соответствующие права доступа! Если вам действительно необходимо извлекать объекты Python из файлов, но вы не можетедоверять источнику этих файлов, идеальным решением будет использованиемодуля pickle, входящего в состав стандартной библиотеки Python.Модуль pickle позволяет сохранять в файлах практически любые объектыPython без необходимости с нашей стороны выполнять какие-либо преобразо-297Файлывания. Он напоминает суперуниверсальную утилиту форматирования и преобразования данных.
Чтобы сохранить словарь в файле, например, мы передаемего непосредственно в функцию модуля pickle:>>>>>>>>>>>>>>>D = {‘a’: 1, ‘b’: 2}F = open(‘datafile.pkl’, ‘wb’)import picklepickle.dump(D, F)# Модуль pickle запишет в файл любой объектF.close()Чтобы потом прочитать словарь обратно, можно просто еще раз воспользоваться возможностями модуля pickle:>>> F = open(‘datafile.pkl’ 'rb')>>> E = pickle.load(F)# Загружает любые объекты из файла>>> E{‘a’: 1, ‘b’: 2}Нам удалось получить назад точно такой же объект словаря без необходимостивручную выполнять какие-либо преобразования. Модуль pickle выполняет то,что называется сериализацией объектов, – преобразование объектов в строкубайтов и обратно, не требуя от нас почти никаких действий.
В действительности, внутренняя реализация модуля pickle выполнила преобразование нашегословаря в строку, при этом незаметно для нас (и может выполнить еще болеезамысловатые преобразования при использовании модуля в других режимах):>>> open(‘datafile.pkl’, ‘rb’).read()# Формат может измениться!b’\x80\x03}q\x00(X\x01\x00\x00\x00aq\x01K\x01X\x01\x00\x00\x00bq\x02K\x02u.’Поскольку модуль pickle умеет реконструировать объекты из строкового представления, нам не требуется самим возиться с этим. Дополнительную информацию о модуле pickle вы найдете в руководстве по стандартной библиотекеязыка Python или попробовав импортировать модуль в интерактивном сеансеи передав его имя функции help. Когда будете заниматься исследованием этогомодуля, обратите также внимание на модуль shelve – инструмент, который использует модуль pickle для сохранения объектов Python в файлах с доступом поключу, описание которых далеко выходит за рамки этой книги (впрочем, пример использования модуля shelve вы найдете в главе 27; кроме того, дополнительные примеры использования модуля pickle приводятся в главах 30 и 36).Обратите внимание, что в примере выше я открыл файл, где хранится сериализованный объект, в двоичном режиме.
В Python 3.0такие файлы всегда следует открывать именно в двоичном режиме, потому что модуль pickle создает и использует объектытипа bytes, а эти объекты предполагают, что файл открыт в двоичном режиме (в версии 3.0 при работе с текстовыми файламииспользуются строки типа str). В более ранних версиях Pythonдопускается использовать текстовые файлы, когда выбираетсяпротокол 0 (используется по умолчанию и создает текстовыефайлы в кодировке ASCII), при условии непротиворечивого использования текстового режима.
Протоколы с более высокиминомерами допускают возможность работы только с двоичнымифайлами. В Python 3.0 по умолчанию используется протокол 3(двоичный), но в этой версии интерпретатора модуль pickle соз-298Глава 9. Кортежи, файлы и все остальноедает строки типа bytes даже при использовании протокола 0. Дополнительные подробности по этой теме вы найдете в главе 36,в справочном руководстве по библиотеке языка Python илив других источниках.В версии Python 2.6 дополнительно имеется модуль cPickle –оптимизированная версия модуля pickle, который можно импортировать для повышения скорости.
В Python 3.0 этот модульпереименован в _pickle и автоматически используется модулемpickle – сценарии просто импортируют модуль pickle и позволяют интерпретатору самому оптимизировать свою работу.Сохранение и интерпретацияупакованных двоичных данных в файлахПрежде чем двинуться дальше, необходимо рассмотреть еще один аспект работы с файлами: в некоторых приложениях приходится иметь дело с упакованными двоичными данными, которые создаются, например, программамина языке C.
Стандартная библиотека языка Python включает инструмент, способный помочь в этом, – модуль struct, который позволяет сохранять и восстанавливать упакованные двоичные данные. В некотором смысле, это совершенно другой инструмент преобразования данных, интерпретирующий строкив файлах как двоичные данные.Например, чтобы создать файл с упакованными двоичными данными, откройте его в режиме ‘wb’ (������������������������������������������������������write�������������������������������������������������binary������������������������������������������������������������������������������������������ – запись двоичных данных) и передайте модулю struct строку формата и некоторый объект Python. В следующем примереиспользуется строка формата, которая определяет пакет данных, содержащий4-байтовое целое число, 4-символьную строку и 2-байтовое целое число, причем все представлены в формате big-endian – в порядке следования байтов «отстаршего к младшему» (существуют также спецификаторы форматов, которыеподдерживают наличие символов дополнения слева, числа с плавающей точкой и многие другие):>>> F = open(‘data.bin’, ‘wb’) # Открыть файл для записи в двоичном режиме>>> import struct>>> data = struct.pack(‘>i4sh’, 7, ‘spam’, 8) # Создать пакет двоичных данных>>> datab’\x00\x00\x00\x07spam\x00\x08’>>> F.write(data)# Записать строку байтов>>> F.close()Интерпретатор Python создаст строку bytes двоичных данных, которую затеммы запишем в файл обычным способом (строка состоит из экранированных последовательностей, представляющих шестнадцатеричные значения).
Чтобыпреобразовать эти значения в обычные объекты языка �����������������������Python�����������������, достаточно просто прочитать строку обратно и распаковать ее с использованием той же строкиформата. Следующий фрагмент извлекает значения, преобразуя их в обычныеобъекты (целые числа и строка):>>> F = open(‘data.bin’, ‘rb’)>>> data = F.read()# Получить упакованные двоичные данные>>> datab’\x00\x00\x00\x07spam\x00\x08’299Файлы>>> values = struct.unpack(‘>i4sh’, data) # Преобразовать в объекты>>> values(7, ‘spam’, 8)Файлы с двоичными данными относятся к категории низкоуровневых средств,которые мы не будем рассматривать подробно.
За дополнительной информацией обращайтесь к главе 36 и к руководству по библиотеке языка Python илиимпортируйте модуль struct в интерактивном сеансе и передайте имя structфункции help. Обратите также внимание, что режимы доступа к двоичнымфайлам ‘wb’ и ‘rb’ могут использоваться для обработки простейших двоичныхфайлов, таких как изображения или аудиофайлы, без необходимости выполнять распаковку их содержимого.Менеджеры контекста файловВам также необходимо будет прочитать обсуждение поддержки менеджеровконтекста файлов в главе 33, впервые появившейся в версиях Python 3.0 и 2.6.Даже при том, что менеджеры контекста в основном применяются для обработки исключений, тем не менее они позволяют обертывать программный код,выполняющий операции с файлами, дополнительным слоем логики, которыйгарантирует, что после выхода за пределы блока инструкций менеджера файлбудет закрыт автоматически, и позволяет не полагаться на автоматическое закрытие файлов механизмом сборки мусора:with open(r’C:\misc\data.txt’) as myfile: # Подробности в главе 33for line in myfile:...операции над строкой line...Аналогичную функциональность предоставляет конструкция try/finally,с которой мы познакомимся в главе 33, но за счет избыточного программногокода – три дополнительных строки, если быть более точным (впрочем, мы можем не использовать ни один из вариантов и позволить интерпретатору самомузакрывать файлы):myfile = open(r’C:\misc\data.txt’)try:for line in myfile:...операции над строкой line...finally:myfile.close()Поскольку для подробного описания обоих способов необходимо иметь дополнительные знания, которыми мы еще не обладаем, мы обсудим в книге эти детали позже.Другие инструменты для работы с файламиКак показано в табл. 9.2, существуют более сложные инструменты для работыс файлами, более того, существуют и другие инструменты, которые отсутствуют в таблице.
Например, функция seek переустанавливает текущую позициюв файле (для следующей операции чтения или записи), функция flush принудительно выталкивает содержимое выходных буферов на диск (по умолчаниюфайлы всегда буферизуются) и так далее.300Глава 9. Кортежи, файлы и все остальноеРуководство по стандартной библиотеке и книги, упомянутые в предисловии,содержат полный перечень методов для работы с файлами.
Чтобы кратко ознакомиться с ним, можно также воспользоваться функцией dir или help в интерактивном сеансе, передав ей объект открытого файла (в Python 3.0, но нев Python 2.6, где следует передать имя типа file). Дополнительные примерыработы с файлами вы найдете во врезке «Придется держать в уме: сканирование файлов» в главе 13. В ней приводятся типичные примеры организации циклов для просмотра содержимого файлов и приводятся инструкции, которыемы еще не рассматривали.Следует также отметить, что функция open и объекты файлов, которые она возвращает, являются в языке Python основным интерфейсом к внешним файлам,однако в арсенале Python существуют и другие инструменты, напоминающиефайлы. Назовем некоторые из них:Стандартные потоки ввода-выводаОбъекты уже открытых файлов в модуле sys, такие как sys.stdout (смотритераздел «Инструкция print» в главе 11)Дескрипторы файлов в модуле osЦелочисленные дескрипторы файлов, обеспечивающие поддержку низкоуровневых операций, таких как блокировка файловСокеты, каналы и очереди (FIFO)Объекты, по своим характеристикам напоминающие файлы, используемыедля синхронизации процессов или организации взаимодействий по сетиФайлы с доступом по ключу, известные как «хранилища» («shelves»)Используются для хранения объектов языка Python по ключу (глава 27)Потоки командной оболочкиТакие инструменты, как os.popen и subprocess.Popen, которые�������������������������������поддержива�����������ют возможность запуска дочерних процессов и выполнения операций с ихстандартными потоками ввода-выводаСреди сторонних открытых модулей можно отыскать еще больше инструментов, напоминающих файлы, включая реализацию поддержки обмена данными через последовательный порт в расширении PySerial и поддержки обменаданными с интерактивными программами в системе pexpect.