1-Python - shelve

about

source code: Lib/shelve.py

shelve是用来做数据序列化的模块,操作它就像操作字典一样方便。并且与字典一样,它就像一个key-value格式的数据库,它的key是一串唯一的字符串,而value可以是任意的python对象,包括类实例、递归数据类型等。

基本参数

用法:

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

需要打开的文件名,返回一个文件句柄f,这里可以理解为返回的是一个字典对象。一般的,你可以为打开的文件指定扩展名,如这样的:

f = shelve.open('test')	 # 普通的形式
f = shelve.open('test.txt')  # 可以指定扩展名
  • flag

该flag参数的解释参考dbm.open(),其中:

Value Meanig
r 打开现有数据库以进行只读(默认)
w 打开现有数据库进行读写
c 打开数据库进行读写,如果不存在则创建它
n 始终创建一个新的空数据库,打开以进行读写
  • protocol

shelve在序列化时依赖pickle,而其中有个protocol参数需要引起我们的注意,那么protocol是什么呢?协议!如果你对pickle有所了解的话,那么你一定知道pickle的两个常量pickle.HIGHEST_PROTOCOLpickle.DEFAULT_PROTOCOL。这两个常量都是整数。当使用pickle或者json将一个对象或者数据结构转化为特定的数据流格式,用于存储或者传输。这个转化的过程称为序列化的过程,序列化又要遵循协议——protocol。比如pickle.dump时,需要一个protocol参数,来指定序列化时遵循的协议。目前有5种协议方案,协议版本越高,处理生成的对象所需要的Python版本就越高。

协议版本 描述
0 该版本是原始的人类可读协议,并且向后兼容早期版本的Python。
1 该版本是是旧的二进制格式,它也与早期版本的Python兼容。
2 在Python 2.3中引入了协议版本2。它提供了更有效的新式类型的protocol。参考PEP 307获取有关协议2带来的改进的信息。
3 在Python 3.0中添加了协议版本3。它具有对bytes对象的显式支持, 并且不能被Python 2.x打开。这是默认协议,需要与其他Python 3版本兼容时的推荐协议。
4 在Python 3.4中添加了协议版本4。它增加了对非常大的对象的支持,挑选更多种类的对象,以及一些数据格式优化。参考PEP 3154获取有关协议4带来的改进的信息。

而当你如果不指定protocol版本时,则使用默认的协议版本3,也就是pickle.DEFAULT_PROTOCOL。同理,shelve在协议版本中与pickle一致。你甚至可以理解为shelve进一步封装了pickle。

  • writeback

简单来说,在writebackFalse的情况下,shelve返回的字典对象无法知道你何时修改字典中的某个value

import shelve
f = shelve.open('test')
f['oldboy'] = {'name': 'oldboy'}
print(f['oldboy'])  # {'name': 'oldboy'}
f['oldboy'].update({'age': 84})
print(f['oldboy'])  # {'name': 'oldboy'}
f.close()

上例所示,第3行手动为字典对象f添加一个oldoby键,对应的value同样是一个字典;第4行打印结果所示添加成功。在第5行按照字典的语法更新oldboy对应的value;但第6行打印却告诉我们更新失败。怎么办呢?这种情况下,我们只能显式的去更新字典。

import shelve
f = shelve.open('test')
f['oldboy'] = {'name': 'oldboy'}
print(f['oldboy'])  # {'name': 'oldboy'}
temp_dict = f['oldboy']
temp_dict.update({'age': 84})
f['oldboy'] = temp_dict
print(f['oldboy'])  # {'name': 'oldboy', 'age': 84}
f.close()

是的,在第5行首先将oldboy键对应的value取出来;第6行做更新操作;第7行从新赋值回去。这样就可以了。但是,相对的,这样比较麻烦,所以,我们可以这么办。

import shelve
f = shelve.open('test', writeback=True)
f['oldboy'] = {'name': 'oldboy'}
print(f['oldboy'])  # {'name': 'oldboy'}
f['oldboy'].update({'age': 84})
print(f['oldboy'])  # {'name': 'oldboy', 'age': 84}
f.close()

如上例,只需要将writeback参数设为True即可。这是怎么回事呢?举个例子,writeback就像手机的同步功能一样,默认是关闭的writeback=False,有需要同步的时候,你显式的点击同步按钮进行同步保存(如上面的显式的更新字典)。也可以设置自动同步writeback=True,省事是省事,就是耗费大量的内存资源。

常用方法

  • shelve.open()
import shelve
shelve.open('test')

shelve模块通过调用shelve.open方法打开文件并获取字典对象。

  • f.close()

正如上面的几个例子,在shelve.open方法打开文件并获取字典对象后,我们要在操作完毕后显式的的关闭文件。

  • with语句

你可能跟我一样有时候忘记f.close()了,是的, shelve模块可以支持with ... as语句。

import shelve
with shelve.open('test') as f:
    f['zhangkai'] = 666    
  • f.get()

我们如果想要获取某个键,该如何呢?

import shelve
with shelve.open('test') as f:
    f['zhangkai'] = 666
    print(f.get('zhangkai'))  # 666

上例,通过f.get()方法来获取某个键对应的值。拿要是想要获取所有的键该如何做呢?往下看。

  • f.keys()

f.keys()返回字典对象得所有key

import shelve
f = shelve.open('test')
print(f.keys())  # KeysView(<shelve.DbfilenameShelf object at 0x00BDEA10>)
print(list(f.keys()))  # ['oldboy']
f.close()

上例中,第3行,f.keys()方法将所有的key都封装到一个对象中,要想看具体的key需要显式的如第4行一样通过list()以列表的形式返回字典中所有的key

  • f.sync
import shelve
f = shelve.open('test', writeback=True)
f.sync()

如果writeback=True的情况下,则写回存中的所有条目。如果可行的话,还清空缓存并在磁盘上同步持久字典。当字典对象需要关闭时会自动调用f.close()。这在某些情况下会很好用。

基本操作

  • 成员测试:in
import shelve
f = shelve.open('test')
print('oldboy' in f.keys())  # True
import shelve
f = shelve.open('test')
class A: pass
a = A()
f['l'] = [1, 2, 3]
f['t'] = (1, 2, 3)
f['d'] = {'张开': '帅帅帅', '自恋狂': '抠脚!'}
f['se'] = {1, 2, 3}
f['st'] = '张开666'
f['obj'] = a
print(f['l'])  # [1, 2, 3]
print(f['t'])  # (1, 2, 3)
print(f['d'])  # {'张开': '帅帅帅', '自恋狂': '抠脚!'}
print(f['se'])  # {1, 2, 3}
print(f['st'])  # 张开666
print(f['obj'])  # <__main__.A object at 0x031E9510>
f.close()

通过上例可以看到,shelve字典的value支持所有的Python数据格式。

import shelve
with shelve.open('test') as f:
    f['zhangkai'] = 666
    print(f.get('zhangkai'))  # 666
    del f['zhangkai']
    print(f.get('zhangkai'))  # None

上例中,通过del来删除字典中的key

import shelve
with shelve.open('test', writeback=True) as f:
    f['zhangkai'] = 666
    f['zhangkai'] = 888
    print(f.get('zhangkai'))  # 888

如上例所示,我们通过writeback参数来自动的修改值。或者你也可以如上面得例子中一样,显式的将该value拿出来,修改完重新赋值回去。

import shelve
with shelve.open('test') as f:
    f['zhangkai'] = 666
    print(f['zhangkai'])  # 666
    temp = f['zhangkai']
    temp = 888
    f['zhangkai'] = temp
    print(f.get('zhangkai'))  # 888
import shelve
with shelve.open('test') as f:
    f['zhangkai'] = 666
    print(f['zhangkai'])  # 666
    print(f['zhangkai1'])  # KeyError: b'zhangkai1'
    print(f.get('zhangkai'))  # 888
    print(list(f.keys()))  # ['oldboy', 'l', 't', 'd', 'se', 'st', 'obj', 'zhangkai']

演示到这里,你可能已经明白了,我们其实是在复习字典的基础操作而已!只是套了个shelve马甲而已。需要补充的是,第4行直接取key时,如果该key不存在则报KeyError,如第5行所示,而第6行通过f.get()方法不存在则返回Nnoe,这一点与字典别无二致。


see also:shelve|dbm|pickle

posted @ 2019-02-13 21:47  听雨危楼  阅读(557)  评论(0编辑  收藏  举报