Сериализация в действии Python

serializaciya v dejstvii python Базы данных и постоянное хранение

Несмотря на то, что сериализованные объекты могут переправляться самыми необычными способами, тем не менее, в наиболее обычном случае для сериализации объекта в плоский файл нужно открыть файл в режиме записи и вызвать функцию dump:

C:\…\PP4E\Dbase> python

>  >> table = {‘a’: [1, 2, 3],

‘b’: [‘spam’, ‘eggs’],

‘c’: {‘name’:’bob’}}

>>> 

>  >> import pickle

>  >> mydb = open(‘dbase’, ‘wb’)

>  >> pickle.dump(table, mydb)

Обратите внимание на наличие здесь вложенных объектов — объект Pick1er способен обрабатывать объекты произвольной структуры. Отметьте также, что файл открывается в двоичном режиме. В Python 3.X это является обязательным условием, потому что сериализованные объекты всегда представлены в виде строки bytes. Чтобы выполнить обратное преобразование в другом сеансе или при последующих запусках приложения, достаточно просто открыть файл и вызвать load:

C:\\PP4E\Dbase> python

>   >> import pickle

>   >> mydb = open(‘dbase’, ‘rb’)

>   >> table = pickle.load(mydb)

>   >> table

{‘a’: [1, 2, 3], ‘c’: {‘name’: ‘bob’}, ‘b’: [‘spam’, ‘eggs’]}

Восстановленный объект имеет то же самое содержимое и ту же структуру, что и оригинал, но он создается в другой области памяти. Это относится и к объектам, воссозданным в том же процессе, и к объектам, воссозданным в другом процессе. Напомню, что для воссозданного объекта выполняется условие ==, но не is:

C:\\PP4E\Dbase> python

>   >> import pickle

>   >> f = open(‘temp’, ‘wb’)

>   >> x = [‘Hello‘, (‘pickle‘, ‘world‘)] # список с вложенным кортежем

>   >> pickle.dump(x, f)

>   >> f.close() # закрыть, чтобы записать на диск

>>> 

>   >> f = open(‘temp’, ‘rb’)

>   >> y = pickle.load(f)

>   >> y

[‘Hello’, (‘pickle’, ‘world’)]

>>> 

>   >> x == y, x is y # то же значение, но разные объекты

(True, False)

Чтобы еще больше упростить этот процесс, модуль в примере 17.1 заключает вызовы прямого и обратного преобразований объектов в функции, которые также открывают файлы, хранящие сериализованную форму объекта.

Пример 17.1. PP4E\Dbase\filepickle.py

"Утилиты сохранения и восстановления объектов из плоских файлов" import pickle

def saveDbase(filename, object):

"сохраняет объект в файле"

file = open(filename, ‘wb’)

pickle.dump(object, file) # сохранить в двоичный файл

file.close() # подойдет любой объект, похожий на файл

def loadDbase(filename):

"загружает объект из файла"

file = open(filename, ‘rb’)

object = pickle.load(file) # загрузить из двоичного файла

file.close() # воссоздать объект в памяти

return object

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

C:\\PP4E\Dbase> python

>   >> from filepickle import *

>   >> L = [0]

>   >> D = {‘x’:0, ‘y’:L}

>   >> table = {‘A‘:L, ‘B‘:D} # присутствуют две ссылки на список L

>   >> saveDbase(‘myfile‘, table) # сериализовать в файл

C:\\PP4E\Dbase> python

>   >> from filepickle import *

>   >> table = loadDbase(‘myfile’) # загрузить/воссоздать

>   >> table

{‘A’: [0], ‘B’: {‘y’: [0], ‘x’: 0}}

>   >> table[‘A‘][0] = 1 # изменить совместно используемый объект

>   >> saveDbase(‘myfile‘, table) # перезаписать в файл

C:\\PP4E\Dbase> python

>   >> from filepickle import *

>   >> print(loadDbase(‘myfile‘)) # изменились оба списка L, как и ожидалось {‘A‘: [1], B‘: {‘y‘: [1], x‘: 0}}

Помимо встроенных типов, таких как списки, кортежи и словари, использовавшихся в примерах до сих пор, сериализовать можно также экзем п ляры клас сов. Тем самым обеспечивается естественный способ связать поведение с хранимыми данными (методы классов обрабатывают атрибуты экземпляров) и простой способ миграции (изменения в классе автоматически будут подхвачены хранимыми экземплярами). Ниже приводится короткая демонстрация в интерактивной оболочке:

>>> class Rec:

def __init__(self, hours):
self.hours = hours

def pay(self, rate=50): return self.hours * rate

>>> bob = Rec(40)

>>> import pickle

>>> pickle.dump(bob, open(‘bobrec’, ‘wb’))

>>> 

>>> rec = pickle.load(open(‘bobrec’, ‘rb’))

>>> rec.hours

40

>>> rec.pay()

2000

Принцип действия этого механизма мы подробно рассмотрим, когда будем исследовать хранилища, создаваемые модулем shelve, далее в этой главе — как мы увидим позже, модуль pickle может использоваться непосредственно, но он также является базовым механизмом баз данных shelve и ZODB.

В целом Python может сериализовать почти все, что угодно, за исключением:

     Объектов компилированного программного кода: функций и классов, когда при сериализации известны только их имена, без имен модулей, что не позволяет позднее повторно импортировать их и автоматически подхватить изменения в файлах модулей.

     Экземпляры классов, не выполняющие правила импортируемости: если говорить кратко, классы должны быть доступны для импортирования при загрузке объекта (подробнее об этом будет рассказываться ниже, в разделе «Файлы хранилищ shelve»).

     Экземпляров некоторых встроенных и определяемых пользователем типов, написанных на языке C или зависящих от преходящих состояний операционной системы (например, объекты открытых файлов не могут быть сериализованы).

Если объект не может быть сериализован, возбуждается исключение PicklingError. Напомню, что мы еще вернемся к проблеме сериализуемости объектов и классов, когда будем знакомиться с хранилищами, создаваемыми модулем shelve.

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

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

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