python之shelve模块详解

阅读目录

回到顶部

一、定义

Shelve 是对象持久化保存方法,将对象保存到文件里面,缺省(即默认)的数据存储文件是二进制的。
回到顶部

二、用途

可以作为一个简单的数据存储方案。
回到顶部

三、用法

使用时,只需要使用 open 函数获取一个 shelf 对象,然后对数据进行增删改查操作,在完成工作、并且将内存存储到磁盘中,最后调用 close 函数变回将数据写入文件。
回到顶部

四、关联模块 Anydbm

相同点:
1.anydbm, shelve 都是对象持久化保存方法,将对象保存到文件里面,缺省的数据存储文件是二进制的。这两个模块允许我们将一个磁盘上的文件与一个”dict-like”对象(类字典对象)关联起来,操作这个“dict-like”对象,就像操作 dict 对象一项,最后可以将“dict-like”的数据持久化到文件。
2. 都可以使用 open 函数。
区别:
anydbm 的 key 和 value 的类型必须都是字符串,而 shelve 的 key 要求必须是字符串,value 则可以是任意合法的 python 数据类型。
回到顶部

五、方法

1.shelve.open(filename, flag=’c’, protocol=None, writeback=False): 创建或打开一个 shelve 对象。shelve 默认打开方式支持同时读写操作。
filename 是关联的文件路径。
可选参数 flag,默认为‘c’,如果数据文件不存在,就创建,允许读写;可以是: ‘r’: 只读;’w’: 可读写; ‘n’: 每次调用 open() 都重新创建一个空的文件,可读写。
protocol:是序列化模式,默认值为 None。具体还没有尝试过,从 pickle 的资料中查到以下信息【protocol 的值可以是 1 或 2,表示以二进制的形式序列化】
2.shelve.close()
同步并关闭 shelve 对象。
注意:每次使用完毕,都必须确保 shelve 对象被安全关闭。同样可以使用 with 语句
with shelve.open('spam') as db:
    db['eggs'] = 'eggs'
回到顶部

六、writeback 参数

writeback:默认为 False。当设置为 True 以后,shelf 将会将所有从 DB 中读取的对象存放到一个内存缓存。当我们 close() 打开的 shelf 的时候,缓存中所有的对象会被重新写入 DB。
writeback 方式有优点也有缺点。
优点是减少了我们出错的概率,并且让对象的持久化对用户更加的透明了;但这种方式并不是所有的情况下都需要,首先,使用 writeback 以后,shelf 在 open()的时候会增加额外的内存消耗,并且当 DB 在 close() 的时候会将缓存中的每一个对象都写入到 DB,这也会带来额外的等待时间。因为 shelve 没有办法知道缓存中哪些对象修改了,哪些对象没有修改,因此所有的对象都会被写入。
注意:为了保存增、删、改的内容,建议显示的标明 writeback=True。

# 七、代码示例
# 1. 创建一个 shelf 对象,直接使用 open 函数即可

import shelve
s
= shelve.open('test_shelf.db') #
try:
s[
'kk'] = {'int': 10, 'float': 9.5, 'String': 'Sample data'}
s[
'MM'] = [1, 2, 3]
finally:
s.close()

# 2. 如果想要再次访问这个 shelf,只需要再次 shelve.open() 就可以了,然后我们可以像使用字典一样来使用这个 shelf

import shelve
try:
s
= shelve.open('test_shelf.db')
value
= s['kk']
print(value)
finally:
s.close()

# 3. 对 shelf 对象,增、删、改操作

import shelve
s
= shelve.open('test_shelf.db', flag='w', writeback=True)
try:
# 增加
s['QQQ'] = 2333
# 删除
del s['MM']
# 修改
s['kk'] = {'String': 'day day up'}
finally:
s.close()

# 注意:flag 设置为‘r’- 只读模式,当程序试图去修改一个以只读方式打开的 DB 时,将会抛一个访问错误的异常。异常的具体类型取决于 anydbm 这个模块在创建 DB 时所选用的 DB。异常举例:anydbm.error: need ‘c’ or ‘n’ flag to open new db

# 4. 循环遍历 shelf 对象

import shelve
s
= shelve.open('test_shelf.db')
try:
# 方法一:
for item in s.items():
print ('键 [{}] = 值 [{}]'.format(item[0], s[item[0]]))
# 方法二:
for key, value in s.items():
print(key, value)
finally:
s.close()

# 5. 备注一个错误:
#
open 中的参数 filename,起初认为需要手动新建一个.db,或者.dat 的文件,目前电脑中无任何真正的数据库文件,所以采用了新建 txt 文件,修改后缀的方法创建.db,或者.dat 的文件。
#
解释器报错,提示内容为:"anydbm.error: db type could not be determined",
#
原因是是 filename 已经存在,并且格式与 shelve 不符,所以提示 “db type could not be determined”。
#
解决方法是,删除该文件。首次运行后会自动生成该 filename 文件。
#
6. 稍微复杂些的案例,实现一个简单提问式的数据库

# encoding:utf-8
#
2018/3/8

# 简单的数据库

import sys,shelve

def print_help():
'存储(增加)、查找、更新(修改)、循环打印、删除、退出、帮助'
print('The available commons are: ')
print('store : Stores information about a person')
print('lookup : Looks up a person from ID numbers')
print("update : Update a person's information from ID number")
print('print_all: Print all informations')
print("delete : Delete a person's information from ID number")
print('quit : Save changes and exit')
print('? : Print this message')

def store_people(db):
pid
= input('Please enter a unique ID number: ')
person
= {}
person[
'name'] = input('Please enter the name: ')
person[
'age'] = input('Please enter the age: ')
person[
'phone'] = input('Please enter the phone: ')
db[pid]
= person
print("Store information: pid is %s, information is %s" % (pid, person))

def lookup_people(db):
pid
= input('Please enter the number: ')
field
= input('What would you like to know? (name, age, phone) ')
if pid in db.keys():
value
= db[pid][field]
print("Pid %s's %s is %s" % (pid, field, value))
else:
print('Not found this number')

def update_people(db):
pid
= input('Please enter the number: ')
field
= input('What would you like to update? (name, age, phone) ')
newvalue
= input('Enter the new information: ')
if pid in db.keys():
value
= db[pid]
value[field]
= newvalue
print("Pid %s's %s update information is %s" % (pid, field, newvalue))
else:
print("Not found this number, can't update")

def delete_people(db):
pid
= input('Please enter the number: ')
if pid in db.keys():
del db[pid]
print("pid %s's information delete done" % pid)
else:
print( "Not found this number, can't delete")

def print_all_people(db):
print( 'All information are: ')
for key, value in db.items():
print(key, value)

def enter_cmd():
cmd
= input('Please enter the cmd(? for help): ')
cmd
= cmd.strip().lower()
return cmd

def main():
database
= shelve.open('database201803.dat', writeback=True)
try:
while True:
cmd
= enter_cmd()
if cmd == 'store':
store_people(database)
elif cmd == 'lookup':
lookup_people(database)
elif cmd == 'update':
update_people(database)
elif cmd == 'print_all':
print_all_people(database)
elif cmd == 'delete':
delete_people(database)
elif cmd == '?':
print_help()
elif cmd == 'quit':
return
finally:
database.close()

if name == 'main':
main()

# shelve 模块比 pickle 模块简单,只有一个 open 函数,返回类似字典的对象,可读可写;
# key 必须为字符串,而值可以是 python 所支持的数据类型
# shelve 模块 (**)------ 可以当做数据库用,以后基本不会用,(可以很方面的往文件中写数据类型和读)
import shelve             #存取很方便(可以做一个简单的数据存储方案)
f=shelve.open(r'sheve.txt')
f['stu1_info']={'name':'egon','age':18,'hobby':['piao','smoking','drinking']}   #
f['stu2_info']={'name':'gangdan','age':53}
f['school_info']={'website':'http://www.pypy.org','city':'beijing'}
print(f['stu1_info']['hobby'])f.close()

import shelve
d
=shelve.open(r'a.txt') #生成三个文件分别是:a.txt.bak\a.txt.dat\a.txt.dir
d['tom']={'age':18,'sex':'male'} #存的时候会生成三个文件,不用管,是 python 的一种处理机制
print(d['tom'][<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">sex</span><span style="color: rgba(128, 0, 0, 1)">'</span>]) #可以取出字典中的 key 对应的 value
print(d['tom']) #取出 tom 对应的字典
d.close()

import shelve
d
=shelve.open(r'a.txt',writeback=True) #writeback=True,对子字典修改完后要写回,否则不会看到修改后的结果
d['egon']={'age':18,'sex':'male'} #存的时候会生成三个文件,不用管,是 python 的一种处理机制
d['egon'][<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">'</span>]=20 #将年龄修改为 20
print(d['egon'][<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">age</span><span style="color: rgba(128, 0, 0, 1)">'</span>]) #此时拿到的是修改后的年龄
print(d['egon'][<span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(128, 0, 0, 1)">sex</span><span style="color: rgba(128, 0, 0, 1)">'</span><span style="color: rgba(0, 0, 0, 1)">])
d.close()