Сохранение объектов Python в БД

Модули pickle, shelve и dbm

Возможность сохранения объектов во всех версиях Python обеспечивают три
модуля в стандартной библиотеке:

pickle
Преобразует произвольные объекты на языке Python в строку байтов и обратно.

dbm (в Python 2.6 называется anydbm)
Реализует сохранение строк в файлах, обеспечивающих возможность обращения по ключу.

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

Запись объектов в БД

from person import Person, Manager # Импортирует наши классы
bob = Person(‘Bob Smith’) # Создание объектов для сохранения
sue = Person(‘Sue Jones’, job=’dev’, pay=100000)
tom = Manager(‘Tom Jones’, 50000)

import shelve
db = shelve.open(‘persondb’) # Имя файла хранилища
for object in (bob, sue, tom): # В качестве ключа использовать атрибут name
    db[object.name] = object # Сохранить объект в хранилище
db.close() # Закрыть после внесения изменений

Чтение объектов из БД

>>> import shelve
>>> db = shelve.open(‘persondb’) # Открыть хранилище
>>> len(db) # В хранилище содержится три ‘записи’
3
>>> list(db.keys()) # keys – это оглавление
[‘Tom Jones’, ‘Sue Jones’, ‘Bob Smith’] # Функция list используется, чтобы
# получить список в 3.0
>>> bob = db[‘Bob Smith’] # Извлечь объект bob по ключу
>>> print(bob) # Вызовет __str__ из AttrDisplay
[Person: job=None, name=Bob Smith, pay=0]
>>> bob.lastName() # Вызовет lastName из Person
‘Smith’
>>> for key in db: # Итерации, извлечение, вывод
print(key, ‘=>’, db[key])
Tom Jones => [Manager: job=mgr, name=Tom Jones, pay=50000]
Sue Jones => [Person: job=dev, name=Sue Jones, pay=100000]
Bob Smith => [Person: job=None, name=Bob Smith, pay=0]

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

  • Недостаток заключается в том, что позднее, когда выполняется загрузка экземпляров, классы и их модули должны быть доступны для импортирования. Если говорить более формально, классы сохраняемых объектов должны быть определены на верхнем уровне модуля, который находится в одном из каталогов в пути поиска sys.path (и не должны находиться в модуле __main__ сценария, если только они не используются только в пределах этого модуля). Из-за этих требований, предъявляемых к внешним файлам модулей, в некоторых приложениях для сохранения используются более простые объекты, такие как словари или списки, особенно когда они передаются другим приложениям через Интернет.
  • Преимущество заключается в том, что изменения в реализации класса автоматически будут восприняты экземплярами после их загрузки – часто нет никакой необходимости обновлять сохраненные объекты, потому что обычно изменения касаются только реализации методов класса.

Обновление данных в БД

# Файл updatedb.py: обновляет объект класса Person в базе данных
import shelve
db = shelve.open(‘persondb’) # Открыть хранилище в файле с указанным именем
for key in sorted(db): # Обойти и отобразить объекты в базе данных
print(key, ‘\t=>’, db[key]) # Вывод в требуемом формате
sue = db[‘Sue Jones’] # Извлечь объект по ключу
sue.giveRaise(.10) # Изменить объект в памяти вызовом метода
db[‘Sue Jones’] = sue # Присвоить по ключу,
# чтобы обновить объект в хранилище
db.close() # Закрыть после внесения изменений

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

c:\misc> updatedb.py
Bob Smith => [Person: job=None, name=Bob Smith, pay=0]
Sue Jones => [Person: job=dev, name=Sue Jones, pay=100000]
Tom Jones => [Manager: job=mgr, name=Tom Jones, pay=50000]
c:\misc> updatedb.py
Bob Smith => [Person: job=None, name=Bob Smith, pay=0]
Sue Jones => [Person: job=dev, name=Sue Jones, pay=110000]
Tom Jones => [Manager: job=mgr, name=Tom Jones, pay=50000]