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.

Если параметр writebackTrue, объект будет хранить кэш всех записей, к которым был осуществлен доступ, и записывать их обратно в 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()                  # закрыть его

См.также

Модуль dbm
Общий интерфейс к базам данных в стиле dbm.
Модуль pickle
Сериализация объекта, используемая shelve.