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 。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/pymotw/shelve-p...

译文地址:https://learnku.com/docs/pymotw/shelve-p...

上一篇 下一篇
讨论数量: 0
发起讨论 只看当前版本


暂无话题~