序列化与反序列化***
为什么要序列化 ?
定义
pickle库
#序列化实例 import pickle lst = 'a b c'.split() with open('test.txt','wb+')as f: pickle.dump(lst,f) file = 'test.txt' with open(file,'wb')as f: s1 = 99 s2 = 'abc' s3 = ['a','b',['c','d']] pickle.dump(s1,f) pickle.dump(s2,f) pickle.dump(s3,f) with open(file,'rb') as f: s=[] for i in range(3): s.append(pickle.load(f)) print(s)
#对象序列化1 import pickle class AA: ttt = 'ABC' def show(self): print('abc') a1 = AA() sr = pickle.dumps(a1) print('sr={}'.format(sr))#AA a2 = pickle.loads(sr) print(a2.ttt) a2.show() #上面的例子中,其实就保存了一个类名,因为所有的其他东西都是类定义的东西,是不变的, #所以序列化只序列化了一个AA类名。反序列化的时候找到类就可以恢复一个对象。
#对象序列化2 import pickle class AAA: def __init__(self): self.tttt = 'abc' b1 = AAA() sr = pickle.dumps(b1) print('sr={}'.format(sr)) #AAA b2 = pickle.loads(sr) print(b2.tttt) #可以看出这回保存了AAA,tttt和abc,因为这才是每一个对象每次都变化的。但是,反序列化的时候要找到AAA类的定义,才能成功。否则会就会抛出异常。 #可以这样理解:反序列化的时候,类是模子,二进制序列就是铁水。
应用
本地序列化的情况,情况较少。
一般来说,大多数情况都应用在网络中。将数据序列化后通过网络传输到远程节点,远程服务器上的服务将接收到的数据反序列化后,就可以使用了。
但是,要注意一点,远程接收端,反序列化时必须有对应的数据类型,否则就会报错。尤其是自定义类,必须远程得有。
#实验 import pickle class AAA: def __init__(self): self.tttt = 'abc' aaa = AAA() sr = pickle.dumps(aaa) print(sr) print(len(sr)) file = 'text.txt' with open(file,'wb')as f: pickle.dump(aaa,f) #将生产的序列化发送到其他节点运行 with open('text1.txt','rb')as f: a = pickle.load(f) #解决办法 ''' 现在,大多数项目,都不是单机的,也不是单服务的。需要通过网络将数据传送到其他节点上去,这就需要大量的 序列化、反序列化。但是,问题是,Python程序之间还可以都是用pickle解决序列化、反序列化,如果是跨平台、 跨语言、跨协议pickle就不太合适了,就需要公共的协议。例如XML、Json、Protocol Buffer等。 不同协议,效率不同,学习曲线不同,适用不同场景,要根据不同的情况分析选型。 '''
Json
Json的数据类型
实例
{ "person": [ { "name": "tom", "age": 18 }, { "name": "cy", "age": "23" } ], "total": 2 }
json模块
Python与Json
Python支持少量内建数据类型到Json类型的转换
常用方法
dumps json编码
dump json编码并存入文件
loads json解码
load dump解码,从文件读取数据
import json d = {'name':'chengyu','age':20,'interest':['music','movie']} j = json.dumps(d)#传入一个对象,return JSONEncoder print(j) d1 = json.loads(j) print(d1)
注意:一般json编码的数据很少落地,数据都是通过网络传输。传输的时候,要考虑压缩它。
本质上来说它就是个文本,就是个字符串。json很简单,几乎所有语言编程都支持json,因而应用范围很广。
MessagePack(第三方库)
安装
pip install msgpack-python
常用方法
#示例: import msgpack import json d ={'person':[{'name':'tom','age':18},{'name':'cheng','age':23}],'total':2} a = json.dumps(d) print("json格式:{},{}".format(len(a),a)) b = msgpack.packb(d) print("magpack格式:{},{}".format(len(b),b)) d1 = msgpack.unpackb(b) print(d1) d1 = msgpack.unpackb(b,encoding='utf-8') print(d1)
注意:MessagePack简单易用,高效压缩,支持语言丰富。
所以,用它序列化也是一个不错的选择。
作页:
argparse模块
参数分类
基本解析
先来一段最简单的程序
import argparse parser = argparse.ArgumentParser() #获得一个参数解析器 args = parser.parse_args() #分析参数 parser.print_help() #打印帮助
#运行结果 #python test.py -h usage:test.py [-h] optional arguments: -h, --help show this help message and exit
argparse不仅仅做了参数的定义和解析,还自动帮助生成了帮助信息。尤其是usage,可以看到现在定义的参数是不是自己想要的
参数解析器ArgumentParser的参数
位置参数解析
import argparse parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents') #获得一个参数解析器 parser.add_argument('path')#位置参数 args = parser.parse_args() #分析参数 parser.print_help() #打印帮助 print('*'*10,args) #运行结果: ''' usage: ls [-h] path ls: error: the following arguments are required: path '''
''' 程序等定义为: ls [-h] path -h为帮助,可有可无 path为位置参数,必须提供 '''
传参
import argparse parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents') #获得一个参数解析器 parser.add_argument('path')#位置参数 args = parser.parse_args(('/etc',)) #分析参数,同时传入可迭代的参数 parser.print_help() #打印帮助 print('*'*3,args) #打印名词空间中收集的参数 #运行结果: ''' usage: ls [-h] path list directory contents positional arguments: path optional arguments: -h, --help show this help message and exit *** Namespace(path='/etc') ''' #注意:Namespace(path='/etc')里面的path可以通过Namespace对象访问,例如args.path
非必须位置参数
#改进1 import argparse #获取一个参数解析器 parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents') parser.add_argument('path',nargs='?',default='.',help='path help')#位置参数,可有可无,缺省值,帮助 args = parser.parse_args()#分析参数,同时传入可迭代的参数 print(args) #打印名词空间中收集的参数 parser.print_help()#打印帮助 '''#运行结果 Namespace(path='path') usage: ls [-h] [path] list directory contents positional arguments: path path help optional arguments: -h, --help show this help message and exit '''
选项参数
-l的实现
-a的实现
#改进2 import argparse #获取一个参数解析器 parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents') parser.add_argument('path',nargs='?',default='.',help='path help')#位置参数,可有可无,缺省值,帮助 parser.add_argument('-l',action='store_true',help='use a long listing format') parser.add_argument('-a','--all',action='store_true',help='show all files,do not ignore entries starting with .') args = parser.parse_args()#分析参数,同时传入可迭代的参数 print(args) parser.print_help() '''运行结果: Namespace(all=False, l=False, path='path') usage: ls [-h] [-l] [-a] [path] list directory contents positional arguments: path path help optional arguments: -h, --help show this help message and exit -l use a long listing format -a, --all show all files,do not ignore entries starting with . ''' #parser.parse_args('-l -a /tmp'.split())语句的运行结果如下: #Namespace(all=True, l=True, path='/tmp')
ls业务功能的实现
1 #最终版 2 import argparse 3 from pathlib import Path 4 from datetime import datetime 5 import stat 6 7 # print(args)#d打印名词空间中收集的参数 8 # parser.print_help()#打印帮助 9 10 #获取文件类型 11 def _getfiletype(f:Path): 12 if f.is_dir(): 13 return 'd' 14 elif f.is_block_device(): 15 return 'b' 16 elif f.is_char_device(): 17 return 'c' 18 elif f.is_socket(): 19 return 's' 20 elif f.is_symlink(): 21 return 'l' 22 else: 23 return '-' 24 25 modelist = ['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x'] 26 def _getmodestr(mode:int): 27 m = int(mode) & 0o777 28 print(mode,m,bin(m)) 29 mstr ='' 30 # for i,v in enumerate(bin(m)[-9:]): 31 # if v == '1': 32 # mstr += modelist[i] 33 # else: 34 # mstr += '-' 35 for i in range(8,-1,-1): 36 if m >>i & 1: 37 mstr += modelist[8-i] 38 else: 39 mstr += '-' 40 return mstr 41 42 #目标:-rw-rw-r-- 1 python python 5 Oct 25 00:07 test4 43 #return (mode,st.st_uid,st.st_gid,size,atime,file.name) 44 def list_dir(path,all=False,detail=False,human=False): 45 46 #return "{}{}".format(size, units[depth] 即换算后的文件大小 47 units = ['', 'K', 'M', 'G', 'T', 'P'] # ' KMGTP' 48 def _gethuman(size: int): 49 depth = 0 50 while size >= 1000: 51 size = size // 1000 52 depth += 1 53 54 return "{}{}".format(size, units[depth]) 55 56 #yield (mode,st.st_uid,st.st_gid,size,atime,file.name) 57 def _showdir(path='',all=False,detail=False,human=False): 58 '''列出本文件目录''' 59 p = Path(path) 60 for file in p.iterdir(): 61 if not all and str(file.name).startswith('.'):#不显示隐藏文件 62 continue 63 if not detail: 64 yield (file.name,) 65 else: 66 #mode 硬链接 属主 属组 字节 时间 name 67 st = file.stat() 68 #调用内部函数stat.filemode,功能等同于自定义getfiletype函数 69 mode = stat.filemode(st.st_mode) 70 size = str(st.st_size) 71 if human: 72 size = _gethuman(st.st_size) 73 atime = datetime.fromtimestamp(st.st_atime).strftime('%Y-%m-%d %H:%M:%S') 74 yield (mode,st.st_nlink,st.st_uid,st.st_gid,size,atime,file.name) 75 76 yield from sorted(_showdir(args.path,args.all,args.l,args.s),key=lambda x:x[-1])#等同于下面语句 77 # for x in sorted(_showdir(args.path,args.all,args.l,args.human),key=lambda x:x[-1]): 78 # yield x 79 #获取一个参数解析器 80 parser = argparse.ArgumentParser(prog='ls',add_help=True,description='list directory contents') 81 parser.add_argument('path',nargs='?',default='.',help='path help')#位置参数,可有可无,缺省值,帮助 82 parser.add_argument('-l',action='store_true',help='use a long listing format') 83 parser.add_argument('--all','-a',action='store_true',help='show all files,do not ignore entries ') 84 parser.add_argument('-s',action='store_true') 85 86 87 if __name__ == '__main__': 88 args = parser.parse_args() # 分析参数,同时传入可迭代的参数 89 parser.print_help() 90 print('*'*10,args) 91 for st in list_dir(args.path,args.all,args.s,args.l): 92 print(st)
其他的完善