Skip to main content

12.3. shelve — Python对象持久化

源代码: Lib/shelve.py


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

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

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

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

由于Python语义,搁架不能知道何时修改了可变的持久字典条目。默认情况下,修改的对象在分配到货架时写入 only (请参阅 )。如果可选的 writeback 参数设置为 True,则所访问的所有条目也被高速缓存在存储器中,并且写回到 sync()close();这可以使得在持久化字典中改变可变的条目变得更加容易,但是,如果访问许多条目,则它可以消耗大量的高速缓存的存储器,并且它可以使关闭操作非常慢,因为所有访问的条目被回写没有办法确定哪些被访问的条目是可变的,哪些被实际上被变异)。

注解

不要依靠架子自动关闭;当你不再需要它时,总是明确地调用 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 而失败。

参见

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

12.3.1. 限制

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

  • shelve 模块不支持对架构对象的 concurrent 读/写访问。 (多个同时读取访问是安全的。)当程序具有用于写入的架子时,没有其它程序应该打开以用于读取或写入。 Unix文件锁定可以用来解决这个问题,但这在Unix版本中有所不同,需要了解所使用的数据库实现。

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

collections.abc.MutableMapping 的子类,用于在 dict 对象中存储pickled值。

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

如果 writeback 参数是 True,则对象将保存所访问的所有条目的高速缓存,并在同步和关闭时间将它们写回 dict。这允许对可变条目进行自然操作,但可能消耗更多的内存,并使同步和关闭需要很长时间。

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

Shelf 对象也可以用作上下文管理器,在这种情况下,它将在 with 块结束时自动关闭。

在 3.2 版更改: 添加了 keyencoding 参数;以前,密钥总是以UTF-8编码。

在 3.4 版更改: 添加了上下文管理器支持。

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

暴露 first()next()previous()last()set_location()Shelf 的子类,其在来自 pybsddb 的第三方 bsddb 模块中可用,但不在其他数据库模块中。传递给构造函数的 dict 对象必须支持这些方法。这通常通过调用 bsddb.hashopen()bsddb.btopen()bsddb.rnopen() 中的一个来完成。可选的 protocolwritebackkeyencoding 参数具有与 Shelf 类相同的解释。

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

Shelf 的子类,它接受 filename 而不是类dict类对象。底层文件将使用 dbm.open() 打开。默认情况下,将创建并打开文件以进行读取和写入。可选的 flag 参数具有与 open() 函数相同的解释。可选的 protocolwriteback 参数具有与 Shelf 类相同的解释。

12.3.2. 例

总结接口(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 使用的对象序列化。