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_PROTOCOL
和pickle.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
简单来说,在writeback
为False
的情况下,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
,这一点与字典别无二致。