python模块 shelve--持久化python数据
本文使用的python3.8:https://docs.python.org/zh-cn/3.8/library/shelve.html#module-shelve
1、与json和pickle的不同
- 使用json或者pickle持久化数据,可以dump多次,但每次dump都会覆盖掉之前的,因此load只能取到最后一次dump的数据。
- shelve模块持久化数据时,也可以dump多次。每次dump的数据存放进一个字典中,不覆盖之前的。
- 另外,写程序的时候如果不想用关系数据库那么重量级的操作去存储数据,也可以用到shelve。
2、shelve模块:Python对象持久化
- "Shelf"是一种持久化的类似字典的对象。与"dbm"数据库的区别在于Shelf中的值(不是键!)可以为任意Python对象---即pickle模块能够处理的任何东西。这包括大部分类实例、递归数据类型,以及包含大量共享子对象的对象。键则为字符串。
- 字典所支持的所有方法都被Shelf对象所支持。因此很容易将基于字典的代码转换为需要持久化存储的代码。
-
序列化:数据转成文本的过程被称为“序列化”,即将对象状态转换为可保持或传输的格式的过程。
反序列化:对应的,从序列化的格式中解析对象状态的过程被称为“反序列化”。
1、shelve.open()方法
shelve.open(filename, flag='c', protocol=None, writeback=False)
- 打开一个持久化字典。
- filename指定下层数据库的基准文件名。作为附带效果,会为filename添加一个扩展名并且可能创建更多的文件。默认情况下,下层数据库会以读写模式打开。
- 可选的flag形参的值:'r'以只读方式打开现有数据库(默认);'w'以读写方式打开现有数据库;'c'以读写方式打开数据库,如果不存在则创建它;'n'始终创建一个新的空数据库,以读写方式打开。
- protocol形参来指定pickle协议版本。默认会使用第3版pickle协议来序列化值。
-
由于Python语义的限制,Shelf对象无法确定一个可变的持久化字典条目在何时被修改。
默认情况下只有在被修改对象再赋值给shelf时才会写入该对象。
如果可选的writeback形参设为True,则所有被访问的条目都将在内存中被缓存,并会在sync()和close()时被写入;这可以使得对持久化字典中可变条目的修改更方便,但是如果访问的条目很多,这会消耗大量内存作为缓存,并会使得关闭操作变得非常缓慢,因为所有被访问的条目都需要写回到字典(无法确定被访问的条目中哪个是可变的,也无法确定哪个被实际修改了)
2、Shelf.sync()方法
Shelf.sync()
- 如果Shelf打开时将writeback设为True则写回缓存中的所有条目。如果可行还会清空缓存并将持久化字典同步到磁盘。此方法会在使用close()关闭Shelf时自动被调用。
3、Shelf.close()
Shelf.close()
- 同步并关闭持久化dict对象。对已关闭Shelf的操作将失败并引发ValueError。
- 请不要依赖于Shelf的自动关闭功能;当不再需要时应当总是显式地调用close(),或者使用shelve.open()作为上下文管理器。
with shelve.open('spam') as db: db['eggs'] = 'eggs'
3、shelve的限制
- 可选择使用哪种数据库包(例如dbm.ndbm或dbm.gnu)取决于支持哪种接口。因此使用dbm直接打开数据库是不安全的。如果使用了dbm,数据库同样会(不幸地)受限于它---这意味着存储在数据库中的(封存形式的)对象尺寸应当较小,并且在少数情况下键冲突有可能导致数据库拒绝更新。
- shelve模块不支持对Shelf对象的并发读/写访问。(多个同时读取访问则是安全的。)当一个程序打开一个shelve对象来写入时,不应再有其他程序同时打开它来读取或写入。Unix文件锁定可被用来解决此问题,但这在不同Unix版本上会存在差异,并且需要有关所用数据库实现的细节知识。
4、shelve实现持久化数据
import shelve d = shelve.open(filename) #Open——file可以由低级库添加后缀 d[key] = data #向字典中存放要持久化的数据(如果key已存在,则覆盖旧数据) data = d[key] #读取字典中持久化的数据(如果没有这样的key则引发KeyError) del d[key] #删除字典中持久化的数据(如果没有这样的键则引发KeyError) flag = key in d #如果key存在,则为True klist = list(d.keys()) #所有现有key的列表。 #因为打开d时,没有指定writeback=True,因此d['xx'].append(3)执行后,3并没有被添加 d['xx'] = [0, 1, 2] #d['xx']=[0,1,2] d['xx'].append(3) #d['xx']=[0,1,2]! #因为打开d时,没有指定writeback=True,你需要仔细编码 temp = d['xx'] #temp=[0,1,2]! temp.append(5) #temp=[0,1,2,5]! d['xx'] = temp #d['xx']=[0,1,2,5]! #或者,d=shelve.open(filename,writeback=True),执行d['xx'].append(5)后就会改变d['xx']的值,但它也会消耗更多的内存,使d.close()操作变慢。 d.close() #关闭d
1、将数据写进shelve对象中
#shelvehh.py文件 import shelve class Test: def __init__(self, n): self.n = n d = shelve.open('shelve_test') #打开shelve文件对象 t1 = Test(123) t2 = Test(456) lst = ['python', 'c', 'java'] d["lst"] = lst #将数列存放进shelve对象中 d["t1"] = t1 #将实例存放进shelve对象中 d["t2"] = t2 d.close() #关闭shelve文件对象
2、从shelve文件中读取数据
import shelve import shelvehh d = shelve.open('shelve_test') #打开shelve文件对象 tt1 = d['t1'] #读取shelve文件 tt2 = d['t2'] lsthh = d['lst'] print(tt1.n) print(tt2.n) print(lsthh) d.close() <<< 123 456 ['python', 'c', 'java']