shelve — Сохраняемость Python объектов


«Шелф (Shelf)» — это постоянный объект, подобный словарю. Разница с базами данных «dbm» состоит в том, что значения (не ключи!) в шелфе могут быть по существу произвольными объектами Python, которые могут обрабатываться модулем pickle. Он включает в себя большинство экземпляров классов, рекурсивные типы данных и объекты, содержащие множество общих подобъектов. Ключи — обычные строки.

shelve.open(filename, flag='c', protocol=None, writeback=False)

Открыть постоянный словарь. Указанное имя файла — это базовое имя файла для базовой базы данных. В качестве побочного эффекта к имени файла может быть добавлено расширение и может быть создано более одного файла. По умолчанию основной файл базы данных открыт для чтения и записи. Необязательный параметр flag интерпретируется так же, как параметр flag для dbm.open().

По умолчанию для сериализации значений используются пикли (pickles) версии 3. Версия протокола pickle может быть указана с помощью параметра protocol.

Из-за семантики Python шелф не может знать, когда изменяемая запись постоянного словаря изменена. По умолчанию изменённые объекты записываются только при присвоении шелфу (см. Пример). Если необязательный параметр 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.