shelve — Сохранение объектов в Python

Источник: Lib/shelve.py


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

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

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

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

Из-за семантики Python полка не может знать, когда изменен элемент персистентного словаря. По умолчанию измененные объекты записываются только при назначении на полку (см. Пример). Если необязательный параметр writeback установлен в True, все записи, к которым обращаются, также кэшируются в памяти и записываются обратно на sync() и close(); это может облегчить мутацию мутируемых записей в постоянном словаре, но, если обращается много записей, это может занимать огромное количество памяти для кэша, и это может сделать операцию закрытия очень медленной, поскольку все обращенные записи записываются обратно (нет способа определить, какие обращенные записи являются мутируемыми, и какие из них были действительно мутированы).

Изменено в версии 3.10: pickle.DEFAULT_PROTOCOL теперь используется в качестве протокола pickle по умолчанию.

Изменено в версии 3.11: Принимает path-like object в качестве имени файла.

Примечание

Не полагайтесь на то, что полка будет закрыта автоматически; всегда вызывайте close() явно, когда она вам больше не нужна, или используйте shelve.open() в качестве менеджера контекста:

with shelve.open('spam') as db:
    db['eggs'] = 'eggs'

Предупреждение

Поскольку модуль shelve поддерживается модулем pickle, загрузка полки из недоверенного источника небезопасна. Как и в случае с pickle, загрузка полки может привести к выполнению произвольного кода.

Объекты Shelf поддерживают большинство методов и операций, поддерживаемых словарями (кроме копирования, конструкторов и операторов | и |=). Это облегчает переход от сценариев, основанных на словарях, к сценариям, требующим постоянного хранения.

Поддерживаются два дополнительных метода:

Shelf.sync()

Запишите все записи в кэш, если полка была открыта с параметром writeback, установленным на True. Также очистите кэш и синхронизируйте постоянный словарь на диске, если это возможно. Это вызывается автоматически, когда полка закрывается с close().

Shelf.close()

Синхронизируйте и закройте постоянный объект dict. Операции с закрытой полкой будут завершены с ошибкой ValueError.

См.также

Persistent dictionary recipe с широко поддерживаемыми форматами хранения и скоростью работы с родными словарями.

Ограничения

  • Выбор того, какой пакет базы данных будет использоваться (например, dbm.ndbm или dbm.gnu), зависит от того, какой интерфейс доступен. Поэтому открывать базу данных напрямую с помощью dbm небезопасно. База данных также (к сожалению) подвержена ограничениям dbm, если он используется — это означает, что (маринованное представление) объектов, хранящихся в базе данных, должно быть довольно маленьким, и в редких случаях столкновения ключей могут привести к отказу базы данных от обновления.

  • Модуль shelve не поддерживает последовательный доступ на чтение и запись к объектам на полке. (Несколько одновременных доступов на чтение безопасны.) Когда программа имеет открытую для записи полку, никакая другая программа не должна иметь ее открытой для чтения или записи. Для решения этой проблемы можно использовать блокировку файлов Unix, но она отличается в разных версиях Unix и требует знаний об используемой реализации базы данных.

  • На macOS dbm.ndbm может тихо повредить файл базы данных при обновлении, что может привести к сбоям при попытке чтения из базы данных.

class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')

Подкласс collections.abc.MutableMapping, который хранит маринованные значения в объекте dict.

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

Если параметр writeback равен True, объект будет хранить в кэше все записи, к которым обращался, и записывать их обратно в dict при синхронизации и закрытии. Это позволяет выполнять естественные операции над мутабельными записями, но может занимать гораздо больше памяти и заставлять синхронизацию и закрытие занимать много времени.

Параметр keyencoding - это кодировка, используемая для кодирования ключей перед их использованием с базовым dict.

Объект Shelf также может использоваться в качестве менеджера контекста, в этом случае он будет автоматически закрыт при завершении работы блока with.

Изменено в версии 3.2: Добавлен параметр keyencoding; ранее ключи всегда кодировались в UTF-8.

Изменено в версии 3.4: Добавлена поддержка контекстного менеджера.

Изменено в версии 3.10: pickle.DEFAULT_PROTOCOL теперь используется в качестве протокола pickle по умолчанию.

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, который принимает имя файла вместо диктоподобного объекта. Базовый файл будет открыт с помощью dbm.open(). По умолчанию файл будет создан и открыт как для чтения, так и для записи. Необязательный параметр flag имеет ту же интерпретацию, что и для функции open(). Необязательные параметры protocol и writeback имеют ту же интерпретацию, что и для класса Shelf.

Пример

Вкратце об интерфейсе (key - строка, data - произвольный объект):

import shelve

d = shelve.open(filename)  # open -- file may get suffix added by low-level
                           # library

d[key] = data              # store data at key (overwrites old data if
                           # using an existing key)
data = d[key]              # retrieve a COPY of data at key (raise KeyError
                           # if no such key)
del d[key]                 # delete data stored at key (raises KeyError
                           # if no such key)

flag = key in d            # true if the key exists
klist = list(d.keys())     # a list of all existing keys (slow!)

# as d was opened WITHOUT writeback=True, beware:
d['xx'] = [0, 1, 2]        # this works as expected, but...
d['xx'].append(3)          # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!

# having opened d without writeback=True, you need to code carefully:
temp = d['xx']             # extracts the copy
temp.append(5)             # mutates the copy
d['xx'] = temp             # stores the copy right back, to persist it

# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.

d.close()                  # close it

См.также

Модуль dbm

Общий интерфейс для баз данных dbm-типа.

Модуль pickle

Сериализация объектов, используемая shelve.