第四章 持久存储
1、程序生成数据
strip():从字符串中去除不想要的空白符
man=[]
other=[]
try:
data=open('sketch.txt')
for each_line in data:
try:
(role,line_spoken)=each_line.split(':',1)
#strip()删除line_spoken变量中不需要的空白符
#将去除空白符后的字符串再赋回到自身
line_spoken=line_spoken.strip()
#根据role的值将line_spoken增加到适当的列表中
if role=='Man':
man.append(line_spoken)
elif role=='Other Man':
other.append(line_spoken)
except ValueError:
pass
data.close()
except IOError:
print('The datafile is missing!')
#输出各个列表
print(man)
print(other)
2、以写模式打开文件
Print()的file参数控制将数据发送/保存到哪里
try:
#打开两个文件,分别赋到一个文件对象
man_file=open('man_data.txt','w')
other_file=open('other_data.txt','w')
#使用print将指定的列表保存到指定的磁盘文件
print(man,file=man_file)
print(other,file=other_file)
man_file.close()
other_file.close()
except IOError:
print('File error.')
- IOError会导致数据被破坏,确保关闭文件。
finally组总会执行,不论try/except语句出现异常
try:
#打开两个文件,分别赋到一个文件对象
man_file=open('man_data.txt','w')
other_file=open('other_data.txt','w')
#使用print将指定的列表保存到指定的磁盘文件
print(man,file=man_file)
print(other,file=other_file)
except IOError:
print('File error.')
finally:
#把close调用移到最后,减少数据破坏错误的可能性,确保文件妥善的关闭
man_file.close()
other_file.close()
- 如何发现错误的特定信息
python变量只包含数据对象的一个引用,python中的字符串不可变,元祖为不可变的列表,所有的数据类型都不可变。原来的数据不能改变,还有其他的变量指向它,永远不可能知道还有哪些变量指向某个特定的字符串
locals()返回当前作用域内定义的所有名的一个集合。
向except组传入一个异常对象,并使用as关键字赋到一个标识符
str():访问任何数据对象(支持串转换)的串表示
in操作符用于检查成员关系
“+”操作符:用于字符串时将联结两个字符串,用于数字时将两个数相加
try:
data=open('missing.txt')
print(data.readline(),end='')
#为异常对象给定一个名
except IOError as err:
#使用str()要求异常对象表现为一个字符串
print('File error:'+str(err))
finally:
#in操作符测试成员关系
if 'data' in locals():
#在locals返回的集合中搜索字符串data,找到,则文件成功打开,没有找到,安全调用close()方法。
data.close()
File error:[Errno 2] No such file or directory: 'missing.txt'
- 用with处理文件
with语句利用了一种名为上下文管理协议的python技术,自动处理所有已打开文件的关闭工作,即使出现异常也不例外,也使用as关键字
try:
#打开两个文件,分别赋到一个文件对象
man_file=open('man_data.txt','w')
other_file=open('other_data.txt','w')
#使用print将指定的列表保存到指定的磁盘文件
print(man,file=man_file)
print(other,file=other_file)
except IOError as err:
print('File error:'+str(err))
finally:
#把close调用移到最后,减少数据破坏错误的可能性,确保文件妥善的关闭
if 'man_file' in the locals():
man_file.close()
if 'other_file' in the locals():
other_file.close()
- with模式
try:
with open('man_data.txt','w') as man_file:
print(man,file=man_file)
with open('other_data.txt','w') as other_file:
print(other,file=other_file)
except IOError as err:
print('File error:'+str(err))
print()会模仿python解释器实际存储列表数据的格式来显示数据,展示数据在内存中的“样子”
- 解析数据格式
- 定制代码
标准输出:sys.stdout
print_lol()第四个参数:标识把数据写入哪个位置,一定要为参数提供一个缺省值sys.stdout。这样如果调用这个函数没有指定文件对象,则会依然写至屏幕。
import sys
def print_lol(the_list,indent=False,level=0,fn=sys.stdout):
for each_item in the_list:
if isinstance(each_item,list):
print_lol(each_item,indent,level+1,fn)
else:
if indent:
for tab_stop in range(level):
print("t",end='',file=fn)
print(each_item,file=fn)
import nester
try:
with open('man_data.txt','w') as man_file:
nester.print_lol(man,file=man_file)
with open('other_data.txt','w') as other_file:
nester.print_lol(other,file=other_file)
except IOError as err:
print('File error:'+str(err))
- “腌制数据”
pickle库:保存和加载几乎任何python数据对象,包括列表。dump()保存数据,load()恢复数据,必须以二进制访问模式打开文件。高效的保存和恢复数据的机制,保存到磁盘和磁盘恢复。
import pickle
try:
#将访问模式改为“可写二进制模式”,调用替换为“pickle”
with open('man_data.txt','wb') as man_file, open('other_data.txt','wb') as other_file:
pickle.dump(man,file=man_file)
pickle.dump(other,file=other_file)
except IOError as err:
print('File error:'+str(err))
#pickle接触数据腌制时出现的异常
except pickle.PickleError as perr:
print('Pickle error:'+str(perr))
- 使用pickle的通用文件I/O
第5章 推导数据 处理数据
- 从各个文件将数据读入各自的列表
方法串链:data.strip().split(),strip应用到data中的数据行,去除不想要的空白符,split创建一个列表,得到的列表应用到以上代码的目标标识符。从左到右读
#打开文件
with open('james.txt')as jaf:
#读数据行
data=jaf.readline()
#将数据转换为一个列表
james=data.strip().split(',')
with open('julie.txt') as juf:
data=juf.readline()
julie=data.strip().split(',')
with open('mikey.txt') as mif:
data=mif.readline()
mikey=data.strip().split(',')
with open('sarah.txt')as saf:
data=saf.readline()
sarah=data.strip().split(',')
print(james)
print(julie)
print(mikey)
print(sarah)
- 排序
原地排序:sort(),排序后的数据替换原来的数据
复制排序:sorted(),原数据的顺序依然保留
默认升序,降序可以传入参数reverse=True
- 函数串链 从右到左读
#打开文件
with open('james.txt')as jaf:
#读数据行
data=jaf.readline()
#将数据转换为一个列表
james=data.strip().split(',')
with open('julie.txt') as juf:
data=juf.readline()
julie=data.strip().split(',')
with open('mikey.txt') as mif:
data=mif.readline()
mikey=data.strip().split(',')
with open('sarah.txt')as saf:
data=saf.readline()
sarah=data.strip().split(',')
#创建函数,对时间格式进行清理
def sanitize(time_string):
#in操作符检查字符是否包含一个短横线与冒号
if '-' in time_string:
spliter='-'
elif':' in time_string:
spliter=':'
else:
#如果字符串不需要清理,就什么也不做
return(time_string)
#分解字符串,抽出分钟和秒部分
(mins,secs)=time_string.split(spliter)
return(mins+'.'+secs)
#创建4个开始为空的新列表
clean_james=[]
clean_julie=[]
clean_mikey=[]
clean_sarah=[]
#取原列表中的各个数据项进行清理,然后将清理后的列表追加到适当的列表
for each_t in james:
clean_james.append(sanitize(each_t))
for each_t in julie:
clean_julie.append(sanitize(each_t))
for each_t in mikey:
clean_mikey.append(sanitize(each_t))
for each_t in sarah:
clean_sarah.append(sanitize(each_t))
#输出已经清理后的新列表
print(sorted(clean_james))
print(sorted(clean_julie))
print(sorted(clean_mikey))
print(sorted(clean_sarah))
- 列表推导 简化重复代码:
列表推导:list comprehension 减少将一个列表转换为另一个列表时编写的代码,支持函数编程概念的一个例子
从一个代码转换为另一个列表需要:
- 创建一个新列表存放转换后的数据
- 迭代处理原列表中的每个数据项
- 每次迭代后完成转换
- 将转换后的数据追加到新列表
#打开文件
with open('james.txt')as jaf:
#读数据行
data=jaf.readline()
#将数据转换为一个列表
james=data.strip().split(',')
with open('julie.txt') as juf:
data=juf.readline()
julie=data.strip().split(',')
with open('mikey.txt') as mif:
data=mif.readline()
mikey=data.strip().split(',')
with open('sarah.txt')as saf:
data=saf.readline()
sarah=data.strip().split(',')
#创建函数,对时间格式进行清理
def sanitize(time_string):
#in操作符检查字符是否包含一个短横线与冒号
if '-' in time_string:
spliter='-'
elif':' in time_string:
spliter=':'
else:
#如果字符串不需要清理,就什么也不做
return(time_string)
#分解字符串,抽出分钟和秒部分
(mins,secs)=time_string.split(spliter)
return(mins+'.'+secs)
#列表推导完成转换,再利用sorted()对新列表进行排序
print(sorted([sanitize(t) for t in james]))
print(sorted([sanitize(t) for t in julie]))
print(sorted([sanitize(t) for t in mikey]))
print(sorted([sanitize(t) for t in sarah]))
- 迭代删除重复项
像是一个过滤器,重复项删除过滤器需要在列表创建过程中检查所创建的列表
#把无序且不一致的数据替换为经过清理的有序副本
james=sorted([sanitize(t) for t in james])
julie=sorted([sanitize(t) for t in julie])
mikey=sorted([sanitize(t) for t in mikey])
sarah=sorted([sanitize(t) for t in sarah])
#创建空列表,存放唯一的数据项
unique_james=[]
#在现有数据上迭代处理
for each_t in james:
#如果数据项不在新列表中,追加到列表中
if each_t not in unique_james:
unique_james.append(each_t)
#从列表分片中得到前3个数据项
print(unique_james[0:3])
unique_julie=[]
for each_t in julie:
if each_t not in unique_julie:
unique_julie.append(each_t)
print(unique_julie[0:3])
unique_mikey=[]
for each_t in mikey:
if each_t not in unique_mikey:
unique_mikey.append(each_t)
print(unique_mikey[0:3])
unique_sarah=[]
for each_t in sarah:
if each_t not in unique_sarah:
unique_sarah.append(each_t)
print(unique_sarah[0:3])
- 用集合删除重复项
集合中的数据项是无序的,不允许重复。
工厂函数:用于创建某个类型的新的数据项,set()创建一个新的集合,数据列表中的任何重复项都会被忽略。
#创建函数,对时间格式进行清理
def sanitize(time_string):
#in操作符检查字符是否包含一个短横线与冒号
if '-' in time_string:
spliter='-'
elif':' in time_string:
spliter=':'
else:
#如果字符串不需要清理,就什么也不做
return(time_string)
#分解字符串,抽出分钟和秒部分
(mins,secs)=time_string.split(spliter)
return(mins+'.'+secs)
#创建新函数,接受一个文件名作为唯一的参数
def get_coach_data(filename):
#增加异常处理代码
try:
#打开文件,读取数据
with open(filename)as f:
data=f.readline()
#将数据返回代码之前先对数据完成分解、去除空白符处理
return(data.strip().split(','))
except IOError as ioerr:
#通知用户有错误(如果出现错误),并返回“None”来提示失败
print('File error:'+str(ioerr))
return(None)
#调用函数,将结果赋至列表
sarah=get_coach_data('sarah.txt')
james=get_coach_data('james.txt')
julie=get_coach_data('julie.txt')
mikey=get_coach_data('mikey.txt')
#对sorted形成的列表进行分片,解决重复项问题
print(sorted(set([sanitize(t) for t in james]))[0:3])
print(sorted(set([sanitize(t) for t in julie]))[0:3])
print(sorted(set([sanitize(t) for t in mikey]))[0:3])
print(sorted(set([sanitize(t) for t in sarah]))[0:3])