Особенности сериализации:протоколы, двоичные режимы и модуль _pickle

osobennosti serializacii protokoly dvoichnye rezhimy i modul pickle Базы данных и постоянное хранение

В последних версиях Python в операцию сериализации было введено понятие протоко лов — форматов хранения сериализованных данных. Чтобы определить желаемый протокол, необходимо передать дополнительный параметр функциям сериализации (его не требуется передавать функциям обратного преобразования: протокол определяется автоматически по сериализованным данным):

pickle.dump(object, file, protocol) # или именованный аргумент protocol=N

Сериализация данных может быть выполнена с применением текстового или двоичного протокола — двоичный протокол позволяет получить более эффективный формат, но при этом создаются нечитаемые человеком файлы. По умолчанию в Python 3.X используется исключительно двоичный формат (известный также, как протокол 3). В текстовом режиме (протокол 0) сериализованные данные представляют собой печатаемый текст ASCII, который может читаться человеком (по сути, он представляет собой последовательность инструкций для машины стека), но в Python 3.X в любом случае получается объект bytes. Другие протоколы (протоколы 1 и 2) также создают сериализованные данные в двоичном формате.

В Python 3.X независимо от номера протокола сериализованные данные представляют собой объект bytes, а не str, и именно поэтому при сохранении и чтении их в плоских файлах требуется использовать двоичный режим (причины описываются в главе 4, если вы забыли). Аналогично, имитируя интерфейс объектов файлов, мы должны использовать объекты bytes:

>  >> import io, pickle

>  >> pickle.dumps([1, 2, 3]) # по умолчанию=двоич. протокол

b’\x80\x03]q\x00(K\x01K\x02K\x03e.’

>  >> pickle.dumps([1, 2, 3], protocol=0) # протокол формата ASCII b'(lp0\nL1L\naL2L\naL3L\na.’

>  >> pickle.dump([1, 2, 3], open(‘temp’,’wb’)) # даже если protocol=0, ASCII

>  >> pickle.dump([1, 2, 3], open(‘temp’,’w’)) # при чтении необх. режим ‘rb’ TypeError: must be str, not bytes

>  >> pickle.dump([1, 2, 3], open(‘temp’,’w’), protocol=0)

TypeError: must be str, not bytes

>  >> B = io.BytesIO() # использовать двоичные потоки/буферы

>  >> pickle.dump([1, 2, 3], B)

>  >> B.getvalue()

b’\x80\x03]q\x00(K\x01K\x02K\x03e.’

>  >> B = io.BytesIO() # bytes и для формата ASCII

>  >> pickle.dump([1, 2, 3], B, protocol=0)

>  >> B.getvalue()

b'(lp0\nL1L\naL2L\naL3L\na.’

>  >> S = io.StringIO() # это не объект str

>  >> pickle.dump([1, 2, 3], S) # даже если protocol=0, ASCII

TypeError: string argument expected, got ‘bytes’

>  >> pickle.dump([1, 2, 3], S, protocol=0)

TypeError: string argument expected, got ‘bytes’

За дополнительными сведениями о сериализации обращайтесь к руководству по библиотеке Python — там вы найдете описание дополнительных интерфейсов, которые могут использоваться классами для переопределения поведения этой операции, которые мы не будем рассматривать здесь ради экономии места. Обратите также внимание на модуль marshal, который тоже сериализует объекты, но может обрабатывать только простые типы объектов. Модуль pickle является более универсальным, чем модуль marshal, и обычно более предпочтителен.

Имеется еще один родственный модуль, _pickle, написанная на языке C оптимизация модуля pickle, который автоматически используется модулем pickle, если доступен — его не требуется выбирать вручную или использовать непосредственно. Модуль shelve наследует эту оптимизацию автоматически. Я еще не рассказывал о модуле shelve, но сейчас сделаю это.

Использованная литература:

Марк Лутц — Программирование на Python, 4-е издание, II том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий