8.3. shelve — 实例对象的持久化
目的: shelve 模块实现了对任意可被序列化的 Python 对象进行持久性存储,也提供类字典 API 给我们使用。
当使用关系数据库是一种浪费的时候,shelve 模块可以为 Python 对象提供一个简单的持久性存储选择。就像使用字典一样,通过关键字访问 shelf 对象。其值经过序列化,写入到由 dbm
创建和管理的数据库。
创建一个 Shelf 对象
最简单的使用 shelve
模块的方式是通过 DbfilenameShelf
类。 该类使用 dbm
来存储数据。你可以直接使用该类,或者调用 shelve.open()
方法。
shelve_create.py
import shelve
with shelve.open('test_shelf.db') as s:
s['key1'] = {
'int': 10,
'float': 9.5,
'string': 'Sample data',
}
为了再次访问数据,打开 shelf 并且像字典一样使用它。
shelve_existing.py
import shelve
with shelve.open('test_shelf.db') as s:
existing = s['key1']
print(existing)
如果你运行了上面两个脚本,应该看到:
$ python3 shelve_create.py
$ python3 shelve_existing.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
dbm
模块不支持多个应用同时写入同一数据库。如果你确定客户端不会修改shelf, 请传入 flag='r'
来指定 shelve 以只读方式打开数据库。
shelve_readonly.py
import dbm
import shelve
with shelve.open('test_shelf.db', flag='r') as s:
print('Existing:', s['key1'])
try:
s['key1'] = 'new value'
except dbm.error as err:
print('ERROR: {}'.format(err))
当数据库以只读方式打开时,使用者又尝试着更改数据库,这将引起一个访问出错的异常。这一异常类型依赖于在创建数据库时被 dbm
选择的数据库模块。
$ python3 shelve_readonly.py
Existing: {'int': 10, 'float': 9.5, 'string': 'Sample data'}
ERROR: cannot add item to database
writeback模式
默认情况下,Shelves 不去追踪可变对象的修改。意思就是,如果你改变了已存储在 shelf 中的一个项目的内容,就必须重新存储该项目来更新 shelf 。
shelve_withoutwriteback.py
import shelve
with shelve.open('test_shelf.db') as s:
print(s['key1'])
s['key1']['new_value'] = 'this was not here before'
with shelve.open('test_shelf.db', writeback=True) as s:
print(s['key1'])
在这个例子中,没有对字典里的关键字 'key1'
的内容进行存储,因此,重新打开 shelf 的时候,并未保存所做的改变。
$ python3 shelve_create.py
$ python3 shelve_withoutwriteback.py
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
{'int': 10, 'float': 9.5, 'string': 'Sample data'}
为了自动捕捉储存在 shelf 中的可变对象所发生的改变,可以开启 writeback 模式。 writeback
标志使得 shelf 用内存中缓存来记住从数据库中调出的所有对象。当 shelf 关闭的时候,每一个缓存中的对象会重新写入数据库。
shelve_writeback.py
import shelve
import pprint
with shelve.open('test_shelf.db', writeback=True) as s:
print('Initial data:')
pprint.pprint(s['key1'])
s['key1']['new_value'] = 'this was not here before'
print('\nModified:')
pprint.pprint(s['key1'])
with shelve.open('test_shelf.db', writeback=True) as s:
print('\nPreserved:')
pprint.pprint(s['key1'])
虽然使用 writeback 模式可以减少程序员出错机率,也能更加透明化对象持久性,但是,不是每种情况都要使用 writeback 模式的。当 shelf 打开的时候,缓存就要占据额外的空间,并且,当 shelf 关闭的时候,也会花费额外的时间去将所有缓存中的对象写入到数据库中。即使不知道缓存中的对象有没有改变,都要写回数据库。如果你的应用程序读取数据多于写入数据,那么 writeback 模式将增大不必要的开销。
$ python3 shelve_create.py
$ python3 shelve_writeback.py
Initial data:
{'float': 9.5, 'int': 10, 'string': 'Sample data'}
Modified:
{'float': 9.5,
'int': 10,
'new_value': 'this was not here before',
'string': 'Sample data'}
Preserved:
{'float': 9.5,
'int': 10,
'new_value': 'this was not here before',
'string': 'Sample data'}
指定 Shelf 类型
上面的例子全都使用了默认的 shelf 实现。使用 shelve.open()
直接代替了一种 shelf 实现,是常见用法,尤其是在不关心用哪种数据库存储数据的时候。然而,当我们需要关心这个问题的时候,通常就会直接使用 DbfilenameShelf
或者 BsdDbShelf
,甚至通过 Shelf
新建子类来自定义一种实现。
扩展阅读
- shelve 标准库文档
dbm
--dbm
使用一个可用的 DBM 库来创建一个新的数据库。- feedcache --
feedcache
模块使用shelve
做为默认的存储选项。- shove -- Shove 使用更多的后端格式来实现类似的 API 。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。