shelve — Python 对象持久化

源代码: Lib/shelve.py


“shelf” 是一个持久化的、类似字典的对象。与 “dbm” 数据库的区别在于,shelf 中的值(不是键!)可以是任意的 Python 对象——任何 pickle 模块可以处理的对象。这包括大多数类实例、递归数据类型以及包含大量共享子对象的对象。键是普通的字符串。

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

打开一个持久化字典。指定的 `filename` 是底层数据库的基本文件名。作为副作用,可能会向文件名添加扩展名,并且可能会创建多个文件。默认情况下,底层数据库文件以读写方式打开。可选的 `flag` 参数与 dbm.open() 的 `flag` 参数具有相同的解释。

默认情况下,使用 pickle.DEFAULT_PROTOCOL 创建的 pickle 用于序列化值。pickle 协议的版本可以通过 `protocol` 参数指定。

由于 Python 语义,shelf 无法知道可变持久化字典条目何时被修改。默认情况下,修改后的对象*仅*在分配给 shelf 时才写入(参见示例)。如果可选的 `writeback` 参数设置为 True,则所有访问过的条目也会缓存在内存中,并在 sync()close() 时写回;这使得在持久化字典中修改可变条目更方便,但是,如果访问了许多条目,它可能会消耗大量内存用于缓存,并且它可能会使关闭操作非常慢,因为所有访问过的条目都被写回(无法确定哪些访问过的条目是可变的,也无法确定哪些条目实际被修改过)。

3.10 版本中修改: pickle.DEFAULT_PROTOCOL 现在用作默认的 pickle 协议。

3.11 版本中修改: 文件名接受类路径对象

备注

不要依赖 shelf 自动关闭;当您不再需要它时,请始终显式调用 close(),或者将 shelve.open() 用作上下文管理器。

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

警告

由于 shelve 模块由 pickle 支持,因此从不受信任的源加载 shelf 是不安全的。与 pickle 一样,加载 shelf 可以执行任意代码。

Shelf 对象支持字典支持的大多数方法和操作(复制、构造函数以及运算符 ||= 除外)。这使得基于字典的脚本向需要持久存储的脚本的过渡更加容易。

支持另外两种方法

Shelf.sync()

如果 shelf 以 `writeback` 设置为 True 的方式打开,则将缓存中的所有条目写回。如果可行,还清空缓存并同步磁盘上的持久化字典。当 shelf 通过 close() 关闭时,此操作会自动调用。

Shelf.close()

同步并关闭持久化的 `dict` 对象。对已关闭的 shelf 进行操作将导致 ValueError 失败。

参见

持久化字典食谱,具有广泛支持的存储格式和原生字典的速度。

限制

  • 使用哪个数据库包(例如 dbm.ndbmdbm.gnu)的选择取决于可用的接口。因此,直接使用 dbm 打开数据库是不安全的。数据库也(不幸地)受限于 dbm 的限制(如果使用它)——这意味着存储在数据库中的对象(其 pickled 表示)应该相当小,在极少数情况下,键冲突可能导致数据库拒绝更新。

  • shelve 模块不支持对 shelved 对象的*并发*读/写访问。(多个同时读访问是安全的。)当一个程序打开一个 shelf 进行写入时,不应有其他程序打开它进行读取或写入。可以使用 Unix 文件锁定来解决这个问题,但这在不同的 Unix 版本之间有所不同,并且需要了解所使用的数据库实现。

  • 在 macOS 上,dbm.ndbm 在更新时可能会悄悄地破坏数据库文件,这可能导致在尝试从数据库读取时发生严重崩溃。

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

collections.abc.MutableMapping 的子类,它将 pickled 值存储在 `dict` 对象中。

默认情况下,使用 pickle.DEFAULT_PROTOCOL 创建的 pickle 用于序列化值。pickle 协议的版本可以通过 `protocol` 参数指定。有关 pickle 协议的讨论,请参阅 pickle 文档。

如果 `writeback` 参数为 True,则对象将保留所有访问过的条目的缓存,并在同步和关闭时将其写回 `dict`。这允许对可变条目进行自然操作,但可能会消耗更多内存并使同步和关闭花费很长时间。

`keyencoding` 参数是用于在键与底层字典一起使用之前对其进行编码的编码。

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` 而不是类似字典的对象。底层文件将使用 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 使用的对象序列化。