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']

 

posted @ 2021-05-29 23:37  麦恒  阅读(412)  评论(0编辑  收藏  举报