shelve
— Python 对象持久化¶
源代码: Lib/shelve.py
“shelf” 是一个持久化的、类似字典的对象。与“dbm”数据库的区别在于 shelf 中的值(而不是键!)本质上可以是任意 Python 对象 —— 任何 pickle
模块可以处理的对象。这包括大多数类实例、递归数据类型以及包含许多共享子对象的对象。键是普通的字符串。
- shelve.open(filename, flag='c', protocol=None, writeback=False)¶
打开一个持久化的字典。指定的 filename 是底层数据库的基本文件名。作为副作用,可以向 filename 添加扩展名,并且可以创建多个文件。默认情况下,底层数据库文件以读写模式打开。可选的 flag 参数的解释与
dbm.open()
的 flag 参数相同。默认情况下,使用
pickle.DEFAULT_PROTOCOL
创建的 pickle 用于序列化值。可以使用 protocol 参数指定 pickle 协议的版本。由于 Python 语义,shelf 无法知道何时修改了可变持久字典条目。默认情况下,修改后的对象仅在分配给 shelf 时才会被写入(请参阅 示例)。如果可选的 writeback 参数设置为
True
,则所有访问的条目也会缓存在内存中,并在sync()
和close()
时写回;这可以更方便地在持久字典中修改可变条目,但是,如果访问了许多条目,它可能会消耗大量内存用于缓存,并且由于所有访问的条目都会被写回(无法确定哪些访问的条目是可变的,也无法确定哪些条目实际上被修改了),因此关闭操作可能会非常慢。在 3.10 版本中变更:
pickle.DEFAULT_PROTOCOL
现在用作默认的 pickle 协议。在 3.11 版本中变更: 接受 filename 的 路径类对象。
注意
不要依赖于 shelf 自动关闭;当你不再需要它时,总是显式调用
close()
,或者使用shelve.open()
作为上下文管理器with shelve.open('spam') as db: db['eggs'] = 'eggs'
Shelf 对象支持字典支持的大多数方法和操作(除了复制、构造函数和运算符 |
和 |=
)。这简化了从基于字典的脚本到需要持久化存储的脚本的过渡。
支持两个额外的方法
- Shelf.sync()¶
如果 shelf 在打开时将 writeback 设置为
True
,则写回缓存中的所有条目。如果可行,也清空缓存并将持久字典同步到磁盘。当使用close()
关闭 shelf 时,会自动调用此方法。
- Shelf.close()¶
同步并关闭持久化的 dict 对象。对已关闭的 shelf 进行操作将会失败并抛出
ValueError
异常。
另请参阅
持久化字典配方,该配方具有广泛支持的存储格式,并且具有本机字典的速度。
限制¶
将使用哪个数据库包(例如
dbm.ndbm
或dbm.gnu
)的选择取决于哪个接口可用。因此,使用dbm
直接打开数据库是不安全的。如果使用了dbm
,则数据库也(不幸地)会受到dbm
的限制——这意味着存储在数据库中的对象(的 pickle 表示形式)应该相当小,并且在极少数情况下,键冲突可能会导致数据库拒绝更新。shelve
模块不支持对 shelf 对象进行并发读/写访问。(多个同时读取访问是安全的。)当程序打开一个 shelf 进行写入时,其他程序不应打开它进行读取或写入。可以使用 Unix 文件锁定来解决此问题,但这在不同的 Unix 版本中有所不同,并且需要了解所使用的数据库实现。在 macOS 上,
dbm.ndbm
可以在更新时静默损坏数据库文件,这可能会在尝试从数据库读取时导致硬崩溃。
- class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')¶
collections.abc.MutableMapping
的子类,它将 pickle 的值存储在 dict 对象中。默认情况下,使用
pickle.DEFAULT_PROTOCOL
创建的 pickle 用于序列化值。可以使用 protocol 参数指定 pickle 协议的版本。有关 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
的子类,它接受一个 filename 而不是类似 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