shelve
— Сохраняемость Python объектов
«Шелф (Shelf)» — это постоянный объект, подобный словарю. Разница с базами данных
«dbm» состоит в том, что значения (не ключи!) в шелфе могут быть по существу
произвольными объектами Python, которые могут обрабатываться модулем
pickle
. Он включает в себя большинство экземпляров классов, рекурсивные
типы данных и объекты, содержащие множество общих подобъектов. Ключи —
обычные строки.
-
shelve.
open
(filename, flag='c', protocol=None, writeback=False) Открыть постоянный словарь. Указанное имя файла — это базовое имя файла для базовой базы данных. В качестве побочного эффекта к имени файла может быть добавлено расширение и может быть создано более одного файла. По умолчанию основной файл базы данных открыт для чтения и записи. Необязательный параметр flag интерпретируется так же, как параметр flag для
dbm.open()
.По умолчанию для сериализации значений используются пикли (pickles) версии 3. Версия протокола pickle может быть указана с помощью параметра protocol.
Из-за семантики Python shelve не может знать, когда изменяемая запись постоянного словаря изменена. По умолчанию изменённые объекты записываются только при присвоении шелфу (см. Пример). Если у необязательного параметра writeback установлено значение
True
, все записи, к которым осуществляется доступ, также кэшируются в памяти и записываются обратно вsync()
иclose()
; это может сделать более удобным изменение изменяемых записей в постоянном словаре, но, если осуществляется доступ ко многим записям, это может потреблять огромные объемы памяти для кеша, и это может сделать операцию закрытия очень медленной, поскольку все читаемые записи записываются обратно (невозможно определить, какие доступные записи, являются изменяемыми, а какие — фактически изменёнными).Примечание
Не рассчитывайте, что шелф закроется автоматически; всегда вызывайте
close()
явно, когда он вам больше не нужен, или используйтеshelve.open()
в качестве менеджера контекста:with shelve.open('spam') as db: db['eggs'] = 'eggs'
Предупреждение
Поскольку модуль shelve
поддерживается pickle
, загрузка шелфа
из ненадёжного источника небезопасна. Как и в случае с pickle, загрузка
шелфа может выполнить произвольный код.
Объекты шелфа поддерживают все методы, поддерживаемые словарями. Это упрощает переход от сценариев на основе словаря к сценариям, требующим постоянного хранения.
Поддерживаются два дополнительных метода:
-
Shelf.
sync
() Записывает все записи в кэш, если шелф был открыт с writeback, установленным на
True
. Также очистить кеш и синхронизировать постоянный словарь на диске, если это возможно. Вызывается автоматически, когда шелф закрывается с помощьюclose()
.
-
Shelf.
close
() Синхронизировать и закрыть постоянный объект dict. Операции на закрытом шелфе завершатся ошибкой с
ValueError
.
См.также
Рецепт постоянного словаря с широко поддерживаемыми форматами хранения и скоростью собственных словарей.
Ограничения
- Выбор того, какой пакет базы данных будет использоваться (например,
dbm.ndbm
илиdbm.gnu
), зависит от того, какой интерфейс доступен. Поэтому открывать базу данных напрямую с помощьюdbm
небезопасно. База данных также (к сожалению) подчиняется ограничениямdbm
, если она используется, это означает, что (пиклинг представление) объекты, хранящиеся в базе данных, должны быть довольно маленькими, и в редких случаях конфликты ключей могут привести к тому, что база данных откажется от обновлений. - Модуль
shelve
не поддерживает конкурентный доступ для чтения/записи к шелф объектам. (Множественные одновременные доступы для чтения безопасны.) Когда у программы есть шелф, открытый для записи, никакая другая программа не должна открывать его для чтения или записи. Для решения этой проблемы можно использовать блокировку файлов Unix, но она отличается в разных версиях Unix и требует знаний об используемой реализации базы данных.
-
class
shelve.
Shelf
(dict, protocol=None, writeback=False, keyencoding='utf-8') Подкласс
collections.abc.MutableMapping
, который хранит пиклинг значения в объекте dict.По умолчанию для сериализации значений используются пикли версии 3. Версия протокола pickle может быть указана с помощью параметра protocol. См. документацию
pickle
для обсуждения протоколов pickle.Если параметр writeback —
True
, объект будет хранить кэш всех записей, к которым был осуществлен доступ, и записывать их обратно в dict во время синхронизации и закрытия. Это позволяет выполнять естественные операции с изменяемыми записями, но может потреблять гораздо больше памяти, а синхронизация и закрытие занимают много времени.Параметр keyencoding — это кодировка, используемая для кодирования ключей до их использования с базовым dict.
Объект
Shelf
также можно использовать в качестве менеджера контекста, и в этом случае он будет автоматически закрыт по завершении блокаwith
.Изменено в версии 3.2: Добавлен параметр keyencoding; раньше ключи всегда кодировались в UTF-8.
Изменено в версии 3.4: Добавлена поддержка менеджера контекста.
-
class
shelve.
BsdDbShelf
(dict, protocol=None, writeback=False, keyencoding='utf-8') Подкласс
Shelf
, реализующий методыfirst()
,next()
,previous()
,last()
иset_location()
, доступны в стороннем модулеbsddb
из pybsddb, но не доступны в других модулях базы данных. Переданный конструктору объект dict должен поддерживать данные методы. Обычно для этого нужно вызвать по одному изbsddb.hashopen()
,bsddb.btopen()
илиbsddb.rnopen()
. Дополнительные параметры protocol, writeback и keyencoding имеют ту же интерпретацию, что и для классаShelf
.
-
class
shelve.
DbfilenameShelf
(filename, flag='c', protocol=None, writeback=False) Подкласс
Shelf
, который принимает filename вместо dict-подобного объекта. Базовый файл будет открыт с использованиемdbm.open()
. По умолчанию файл будет создан и открыт как для чтения, так и для записи. Необязательный параметр flag интерпретируется так же, как и функцияopen()
. Необязательные параметры protocol и writeback имеют ту же интерпретацию, что и для классаShelf
.
Пример
Подводя итог интерфейсу (key
— строка, data
— произвольный
объект):
import shelve
d = shelve.open(filename) # open - файл может получить суффикс, добавленный низкоуровневой
# библиотекой
d[key] = data # хранить данные по ключу (перезаписывает старые данные, если
# используя существующий ключ)
data = d[key] # получить КОПИЮ данных по ключу (вызывает KeyError
# если нет такого ключа)
del d[key] # удалить данные, хранящиеся в ключе (вызывает KeyError
# если нет такого ключа)
flag = key in d # true, если ключ существует
klist = list(d.keys()) # список всех существующих ключей (медленно!)
# поскольку d был открыт БЕЗ writeback=True, будьте осторожны:
d['xx'] = [0, 1, 2] # это работает как положено, но ...
d['xx'].append(3) # *это не так!* -- d['xx'] все ещё [0, 1, 2]!
# открыв d без writeback=True, вам нужно тщательно программировать:
temp = d['xx'] # извлекает копию
temp.append(5) # изменяет копию
d['xx'] = temp # сохраняет копию обратно, чтобы сохранить ее
# или d=shelve.open(filename,writeback=True) позволил бы вам простой код
# d['xx'].append(5) и работать как положено, НО это также
# потребляют больше памяти и замедляют работу d.close().
d.close() # закрыть его