搁置 — Python 对象持久性 — Python 文档

来自菜鸟教程
Python/docs/3.8/library/shelve
跳转至:导航、​搜索

shelve — Python 对象持久化

源代码: :source:`Lib/shelve.py`



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

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

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

默认情况下,版本 3 pickles 用于序列化值。 pickle 协议的版本可以通过 protocol 参数指定。

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

笔记

不要依赖货架自动关闭; 当你不再需要它时,总是显式调用 close(),或者使用 shelve.open() 作为上下文管理器:

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

警告

因为 shelf 模块由 pickle 支持,所以从不受信任的来源加载一个架子是不安全的。 与 pickle 一样,加载一个架子可以执行任意代码。


Shelf 对象支持字典支持的所有方法。 这简化了从基于字典的脚本到需要持久存储的脚本的过渡。

支持另外两种方法:

Shelf.sync()
如果架子是在 writeback 设置为 True 的情况下打开的,则写回缓存中的所有条目。 如果可行,还清空缓存并同步磁盘上的持久字典。 当使用 close() 关闭架子时,会自动调用此方法。
Shelf.close()
同步并关闭持久化的 dict 对象。 关闭货架上的操作将失败,并显示 ValueError

也可以看看

持久字典配方具有广泛支持的存储格式并具有本地字典的速度。


限制


  • 选择使用哪个数据库包(例如 dbm.ndbmdbm.gnu)取决于哪个接口可用。 因此直接使用dbm打开数据库是不安全的。 数据库也(不幸地)受到 dbm 的限制,如果使用它——这意味着存储在数据库中的对象(腌制表示)应该相当小,并且在极少数情况下是关键冲突可能导致数据库拒绝更新。
  • shelve 模块不支持 concurrent 对搁置对象的读/写访问。 (多个同时读访问是安全的。)当一个程序有一个为写而打开的架子时,没有其他程序应该打开它以进行读或写。 Unix 文件锁定可用于解决此问题,但这因 Unix 版本而异,并且需要了解所使用的数据库实现。
class shelve.Shelf(dict, protocol=None, writeback=False, keyencoding='utf-8')

collections.abc.MutableMapping 的子类,它在 dict 对象中存储腌制值。

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

如果 writeback 参数为 True,则对象将保存所有访问条目的缓存,并在同步和关闭时间将它们写回 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()来自 pybsddb 的第三方 bsddb 模块,但不在其他数据库模块中。 传递给构造函数的 dict 对象必须支持这些方法。 这通常通过调用 bsddb.hashopen()bsddb.btopen()bsddb.rnopen() 之一来实现。 可选的 protocolwritebackkeyencoding 参数与 Shelf 类具有相同的解释。
class shelve.DbfilenameShelf(filename, flag='c', protocol=None, writeback=False)
Shelf 的子类,它接受 文件名 而不是类似 dict 的对象。 底层文件将使用 dbm.open() 打开。 默认情况下,文件将被创建和打开以进行读取和写入。 可选的 flag 参数与 open() 函数具有相同的解释。 可选的 protocolwriteback 参数与 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 使用的对象序列化。