shelve
— Постоянство объекта Python¶
Исходный код: Lib/shelve.py
«shelf» - это постоянный объект, подобный словарю. Разница с базами данных «dbm» заключается в том, что значения (а не ключи!) в shelf могут быть, по сути, произвольными объектами Python - всем, что может обрабатывать модуль pickle
. Это включает в себя большинство экземпляров классов, рекурсивные типы данных и объекты, содержащие множество общих подобъектов. Ключи - это обычные строки.
- shelve.open(filename, flag='c', protocol=None, writeback=False)¶
Откройте постоянный словарь. Указанное имя файла является базовым для базовой базы данных. В качестве побочного эффекта к имени файла может быть добавлено расширение и может быть создано более одного файла. По умолчанию базовый файл базы данных открыт для чтения и записи. Необязательный параметр flag имеет ту же интерпретацию, что и параметр flag для
dbm.open()
.По умолчанию для сериализации значений используются рассолы, созданные с помощью
pickle.DEFAULT_PROTOCOL
. Версию протокола рассола можно указать с помощью параметра protocol.Из-за семантики Python полка не может знать, когда изменяется изменяемая запись в постоянном словаре. По умолчанию измененные объекты записываются только при назначении на полку (см. Пример). Если для необязательного параметра обратная запись задано значение
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()¶
Запишите обратно все записи в кэш, если полка была открыта с параметром обратная запись, равным
True
. Также очистите кэш и, если возможно, синхронизируйте постоянный словарь на диске. Это вызывается автоматически, когда полка закрывается с помощьюclose()
.
- Shelf.close()¶
Синхронизируйте и закройте постоянный объект dict. Операции с закрытой полкой завершатся ошибкой с
ValueError
.
См.также
Persistent dictionary recipe с широко поддерживаемыми форматами хранения и скоростью работы собственных словарей.
Ограничения¶
Выбор того, какой пакет базы данных будет использоваться (например,
dbm.ndbm
илиdbm.gnu
), зависит от того, какой интерфейс доступен. Поэтому открывать базу данных напрямую с помощьюdbm
небезопасно. База данных также (к сожалению) подвержена ограничениямdbm
, если она используется - это означает, что (выбранное представление) объектов, хранящихся в базе данных, должно быть довольно небольшим, и в редких случаях коллизии ключей могут привести к отказу базы данных в обновлении.Модуль
shelve
не поддерживает одновременный доступ для чтения/записи к отложенным объектам. (Множественный одновременный доступ для чтения безопасен.) Когда в программе есть открытая для записи полка, ни одна другая программа не должна открывать ее для чтения или записи. Для решения этой проблемы можно использовать блокировку файлов Unix, но в разных версиях Unix она различается и требует знаний об используемой реализации базы данных.В Mac OS
dbm.ndbm
может незаметно повредить файл базы данных при обновлении, что может привести к серьезным сбоям при попытке чтения из базы данных.
- class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')¶
Подкласс
collections.abc.MutableMapping
, который хранит выбранные значения в объекте dict.По умолчанию для сериализации значений используются pickles, созданные с помощью
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
, который принимает имя файла вместо объекта, подобного dict. Базовый файл будет открыт с помощью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