М. Лутц - Изучаем Python (4-е издание)- 2011 (1126907), страница 75
Текст из файла (страница 75)
Тот же эффект можно было бы получить с помощью извлечения среза line[:-1], но такой подход можно использовать, только если мы уверены, что все строки завершаются символом \n (последняя строка в файле иногдаможет не содержать этого символа).Пока что мы прочитали ту часть файла, которая содержит строку. Теперь прочитаем следующий блок, в котором содержатся числа, и выполним разбор этого блока (то есть извлечем объекты):>>> line = F.readline()>>> line‘43,44,45\n’>>> parts = line.split(‘,’)# Следующая строка из файла# Это - строка# Разбить на подстроки по запятым296Глава 9. Кортежи, файлы и все остальное>>> parts[‘43’, ‘44’, ‘45\n’]Здесь был использован метод split, чтобы разбить строку на части по запятым,которые играют роль символов-разделителей, – в результате мы получили список строк, каждая из которых содержит отдельное число.
Теперь нам необходимо преобразовать эти строки в целые числа, чтобы можно было выполнятьматематические операции над ними:>>> int(parts[1])# Преобразовать строку в целое число44>>> numbers = [int(P) for P in parts] # Преобразовать весь список>>> numbers[43, 44, 45]Как мы уже знаем, функция int преобразует строку цифр в объект целого числа, а генератор списков, представленный в главе 4, позволяет применить функцию ко всем элементам списка в одной инструкции (подробнее о генераторахсписков читайте далее в этой книге).
Обратите внимание: для удаления завершающего символа \n в конце последней подстроки не был использован методrstrip, потому что int и некоторые другие функции преобразования просто игнорируют символы-разделители, окружающие цифры.Наконец, чтобы преобразовать список и словарь в третьей строке файла, можно воспользоваться встроенной функцией eval, которая интерпретирует строкукак программный код на языке Python (формально – строку, содержащую выражение на языке Python):>>> line = F.readline()>>> line“[1, 2, 3]${‘a’: 1, ‘b’: 2}\n”>>> parts = line.split(‘$’)# Разбить на строки по символу $>>> parts[‘[1, 2, 3]’, “{‘a’: 1, ‘b’: 2}\n”]>>> eval(parts[0])# Преобразовать строку в объект[1, 2, 3]>>> objects = [eval(P) for P in parts] # То же самое для всех строк в списке>>> objects[[1, 2, 3], {‘a’: 1, ‘b’: 2}]Поскольку теперь все данные представляют собой список обычных объектов,а не строк, мы сможем применять к ним операции списков и словарей.Сохранение объектов Python с помощью модуля pickleФункция eval, использованная в предыдущем примере для преобразованиястрок в объекты, представляет собой мощный инструмент.
И иногда даже слишком мощный. Функция 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)Файлы с двоичными данными относятся к категории низкоуровневых средств,которые мы не будем рассматривать подробно.