python3内置持久化模块shelve心得
来自python官方网站的解释:
https://docs.python.org/zh-cn/3.10/library/shelve.html
本文环境: Windows 10 专业版 64 位 + Thonny 3.2.6
概述
内置模块 shelve 可以将任意 Python 对象(即 https://docs.python.org/zh-cn/3.10/library/pickle.html#module-pickle 模块能够处理的任何东西。)以类似字典的对象(shelf 对象)存在磁盘上以实现数据的持久保存。模块 shelve 生成的类似字典的对象 shelf 包含键 key 和 值 value 。类字典对象 shelf 的键 key 是普通的字符串。类字典对象 shelf 的值 value 是任意 python 对象—即 pickle 模块能够处理的任何东西。
【个人猜想 python 使用 shelve 作为数据持久化模块名字的原因】
shelve释义 vt. 将(书等)放置在架子上。通过上述表格可以理解 python 使用 shelve (释义 vt. 将(书等)放置在架子上)作为数据持久化模块名字的原因。把 python 对象加上标签放在磁盘中。
内置持久化模块 pickle 和 shelve 的区别?
内置模块 pickle 是一条一条的存储数据的,没有给数据贴上便于索引的标签。内置模块 shelve 是 pickle 升级,底层用到了 pickle 的方法,把 python 对象贴上标签后存储在磁盘中。
语法
打开一个持久化字典shelve.open()
shelve.open(filename, flag=‘c’, protocol=None, writeback=False)
语句作用:打开一个持久化字典。
参数
filename :必填参数。filename 指定下层数据库的基准文件名。作为附带效果,会为 filename 添加一个扩展名并且可能创建更多的文件。
flag=‘c’ :可选参数。默认值 ‘c’ 读写模式。默认情况下,下层数据库会以读写模式打开。可选的 flag 形参具有与 https://docs.python.org/zh-cn/3.10/library/dbm.html#dbm.open flag 形参相同的含义。
protocol=None :可选参数。默认值 None。在默认情况下,会使用以 https://docs.python.org/zh-cn/3.10/library/pickle.html#pickle.DEFAULT_PROTOCOL 创建的 pickle 来序列化值。 pickle 协议的版本可通过 protocol 形参来指定。
writeback=False :可选参数。默认值 False。由于 Python 语义的限制,Shelf 对象无法确定一个可变的持久化字典条目在何时被修改。 默认情况下 只有 在被修改对象再赋值给 shelf 时才会写入该对象 (参见 https://docs.python.org/zh-cn/3.10/library/shelve.html#shelve-example)。 如果可选的 writeback 形参设为 True,则所有被访问的条目都将在内存中被缓存,并会在 https://docs.python.org/zh-cn/3.10/library/shelve.html#shelve.Shelf.sync 和 https://docs.python.org/zh-cn/3.10/library/shelve.html#shelve.Shelf.close 时被写入;这可以使得对持久化字典中可变条目的修改更方便,但是如果访问的条目很多,这会消耗大量内存作为缓存,并会使得关闭操作变得非常缓慢,因为所有被访问的条目都需要写回到字典(无法确定被访问的条目中哪个是可变的,也无法确定哪个被实际修改了)。
关闭一个持久化字典shelf.close()
shelf.close()
推荐使用上下文管理器with shelve.open(‘spam’) as db:
with shelve.open(‘spam’) as db:
db[‘eggs’] = ‘eggs’
解析:
with shelve.open(‘spam’) as db:
with :上下文管理器, with 会自动关闭文件。
shelve.open() : 模块 shelve 的 open 方法,使用读写模式创建名为 spam 的类字典对象 shelf ,在我的电脑上生成了3个文件: spam.bak 、 spam.dat 、spam.dir 。
这3个文件都用系统自带的记事本打开:
spam.bak :‘egg’, (0, 13)
spam.dat :€X eggq .
spam.dir :‘egg’, (0, 13)
as db :指定用 shelve.open() 打开的类字典文件对象 shelf 的别名是 db 。
db[‘eggs’] = ‘eggs’ : 向类字典对象 shelf 中添加键值对 , 键 ‘egg’ ,值字符串 ‘egg’ 。
示例
来在官网的示例:
解析及翻译:
import shelve
d = shelve.open(filename) # open -- file may get suffix added by low-level library
# 打开 -- 文件可能从尾部加入通过低级别的库
d[key] = data # store data at key (overwrites old data if using an existing key)
# 存储变量名data中的数据value到键key(如果键key已经保存有数据,原有数据会被覆盖)
data = d[key] # retrieve a COPY of data at key (raise KeyError if no such key)
# 从键key中取回数据赋值给变量名data(如果没有键名 key 系统提起 KeyError 错误)
del d[key] # delete data stored at key (raises KeyError if no such key)
# 删除键 key 及数据(如果没有键名 key 系统提起 KeyError 错误)
flag = key in d # true if the key exists
# 使用关键字 in 检测一个键 key 是否在类字典对象 shelf d中
klist = list(d.keys()) # a list of all existing keys (slow!)
# 使用函数 list() 列出类字典对象 shelf d中的全部键 key
# as d was opened WITHOUT writeback=True, beware:
# 类字典对象 shelf d 打开没用使用 writeback=True , 小心:
d['xx'] = [0, 1, 2] # this works as expected, but...
# 向类字典文件对象 shelf d 写入键-值对
# 键 key 'xx' ,值 value 列表 [0, 1, 2]
d['xx'].append(3) # *this doesn't!* -- d['xx'] is STILL [0, 1, 2]!
# 通过列表的内置方法append()试图加入元素3
# 由于 open() 是没有使用参数 writeback = True
# 导致添加元素3失败 -- d['xx'] 的值还是[0, 1, 2]!
# having opened d without writeback=True, you need to code carefully:
# 如果open()文件类字典文件对象 shelf d 是没有使用参数 writeback = True , 你编程时需要小心:
temp = d['xx'] # extracts the copy
# 把类字典对象 shelf d['xx']键中保存的值,赋值给temp
temp.append(5) # mutates the copy
# 对变量 temp 进行列表的 append 操作
d['xx'] = temp # stores the copy right back, to persist it
# 类字典对象 shelf d['xx']的键再次指向 temp
# or, d=shelve.open(filename,writeback=True) would let you just code
# d['xx'].append(5) and have it work as expected, BUT it would also
# consume more memory and make the d.close() operation slower.
# 或者,d=shelve.open(filename,writeback=True)
# d['xx'].append(5) 可以正常工作,但是 writeback=True 会导致
# 消耗更多的内存和关闭文件对象 d.close() 时变慢。
d.close() # close it
# 类字典文件对象 shelf d 关闭
包含常用操作的示例
# 模块 shelve 训练
import shelve
my_str = "abcde"
my_list = [1,2,3,4,5]
my_tuple = (100,200)
my_dict = {
'name':'qs',
'age':18,
}
shelf_object = shelve.open('shelve_test') # 新建一个用模块shelve存储在硬盘上的文件shelve_test
shelf_object['shelf_str1'] = my_str
shelf_object['shelf_list1'] = my_list
shelf_object['shelf_tuple1'] = my_tuple
shelf_object['shelf_dict1'] = my_dict
shelf_object['shelf_str2'] = 'fghijk'
shelf_object.close() # 关闭类字典 shelf 对象,以上数据存储到硬盘上3个文件,
# 名为shelve_test后缀名:bak、dat、dir
with shelve.open('shelve_test') as shelf_object: # 使用上下文管理器 with 打开文件 shelve_test 生成类字典对象 shelf 文件名 db
# 使用了 with python 会自动 close() 类字典文件对象 shelf db
print(list(shelf_object.keys())) # 列出文件 shelve_test 内存储的所有键 keys
print(list(shelf_object.values())) # 列出文件 shelve_test 内出存储的所有值 values
for k,v in shelf_object.items(): # 使用 for 循环和字典的items() 方法遍历键 key 和值 value
print("键:",k)
print("值:",v)
print("**********\n")
flag = 'shelf_str1' in shelf_object # 使用关键字 in 判断键 key 是否在 shelf 文件内
print("判断键是否在文件内 key in shelf_object:",flag)
结果:
>>> %Run shelve_test.py
['my_str', 'my_list', 'shelf_str1', 'shelf_list1', 'shelf_tuple1', 'shelf_dict1', 'shelf_str2']
['abcde', ['abc', 'def'], 'abcde', [1, 2, 3, 4, 5], (100, 200), {'name': 'qs', 'age': 18}, 'fghijk']
键: my_str
值: abcde
**********
键: my_list
值: ['abc', 'def']
**********
键: shelf_str1
值: abcde
**********
键: shelf_list1
值: [1, 2, 3, 4, 5]
**********
键: shelf_tuple1
值: (100, 200)
**********
键: shelf_dict1
值: {'name': 'qs', 'age': 18}
**********
键: shelf_str2
值: fghijk
**********
判断键是否在文件内 key in shelf_object: True
>>>
参数 writeback = True
shelve.open() 默认 writeback = False ,会导致我们修改类字典文件 shelf 的内容失败。可以使用参数 writeback = True 来解决。示例如下:
# 模块 shelve 训练
import shelve
my_dict = {
'name':'qs',
'age':18,
}
with shelve.open('shelve_test') as shelf_object:
shelf_object['key1'] = my_dict # 将字典 my_dict 存入 shelf_object
print("默认值 writeback = False ")
with shelve.open('shelve_test') as shelf_object:
print(shelf_object['key1']) # 字典 my_dict 存入 shelf_object 成功
print("修改前shelf_object['key1']['name']的值:")
print(shelf_object['key1']['name']) # 读出 shelf_object['key1']['name'] 键对应的值成功
shelf_object['key1']['name'] = 'abc' # shelf_object['key1']['name'] 键对应的值赋值为 'abc'
print("修改后shelf_object['key1']['name']的值:")
print(shelf_object['key1']['name']) # shelf_object['key1']['name'] 键对应的值赋值为 'abc' 失败
print(" writeback = True ")
with shelve.open('shelve_test',writeback = True) as shelf_object:
print(shelf_object['key1']) # 字典 my_dict 存入 shelf_object 成功
print("修改前shelf_object['key1']['name']的值:")
print(shelf_object['key1']['name']) # 读出 shelf_object['key1']['name'] 键对应的值成功
shelf_object['key1']['name'] = 'abc' # shelf_object['key1']['name'] 键对应的值赋值为 'abc'
print("修改后shelf_object['key1']['name']的值:")
print(shelf_object['key1']['name']) # shelf_object['key1']['name'] 键对应的值赋值为 'abc' 成功
结果:
>>> %Run shelve_test.py
默认值 writeback = False
{'name': 'qs', 'age': 18}
修改前shelf_object['key1']['name']的值:
qs
修改后shelf_object['key1']['name']的值:
qs
writeback = True
{'name': 'qs', 'age': 18}
修改前shelf_object['key1']['name']的值:
qs
修改后shelf_object['key1']['name']的值:
abc
>>>
如果大家想更深入了解shelve的模块,推荐大家阅读【乐铁】博主创作的文章:
铁乐学python-shelve模块详解,同时感谢【乐铁】博主创作这么好的文章。
文章链接:
https://blog.csdn.net/u012145252/article/details/80028146
1、shelve模块将内存数据以字典的类型(key,value)通过文件持久化,模拟出简单的db效果。
2、shelve模块可以持久化任何pickle可支持的python数据格式,但是它的key必需得是字符串。
3、shelve可以看作是pickle模块的一个封装,但它实现了可以多次dump(后面的dump不会覆盖前面的)和多次load。
4、shelve访问己有key时,实际上取出的是数据源给出的一份拷贝,
所以对于拷贝做出的增加和删除等操作都需要用writeback=True参数才能实现写入回源中进行修改。
5、shelve对于d[key] = data这种操作,视为存储数据,无则新增,有则覆盖,
与访问key对当中的值(条目)进行修改默认不回写并不矛盾和冲突。
6、默认安装环境下,shelve中的r只读模式在python2.7能生效,在3.5环境中则不能生效。
有很大可能是与2.7中存在anydbm模块,而3.5中只存在dbm模块而不存在anydbm有关。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/u012145252/article/details/80028146