为什么要序列化
内存中的字典、列表、集合以及各种对象,如何保存到一个文件中。
设计一套协议,按照某种规则,把内存中的数据保存到文件中,文件是一个个字节序列。所以必须把数据额转换为字节序列,输出到文件,这就是序列化,反之,从文件的字节 序列恢复到内存中,就是反序列化。
1、定义
Serialization系列化,将内存中对象存储下来,把他变成一个个字节。二进制。
deSerialization反序列化,将文件的一个个字节到内存中。
序列胡保存到文件就是持久化。
可将数据序列化后持久化,或者网络传输,也可以将文件中或者网络接受到的字节序列反序列化。
2、pickle库
Python中的序列化、反序列化模块
dumps对象序列化为bytes对象
dump对象序列化到文件对象,就是存入到文件。
loads从bytes对象反序列化。
load对象反序列化,从文件读取数据.
##
import pickle
filename = 'ser'
x= 'a'
y = '100'
z = '100'
with open(filename,'wb') as f:
pickle.dump(x,f)
pickle.dump(y,f)
pickle.dump(z,f)
with open(filename,'rb')as f:
for _ in range(3):
a = pickle.load(f)
print(a,type(a))
还原的时候不一定是完全一样的。
序列化应用:一般来说,本地序列化的情况,应用较少,大多数都是用在网络传输上面的。
将数据序列化后通过网络传输到远程节点,远程服务器上的服务将接受到的数据反序列化后,就可以使用了。
但是,要注意的是,远程接收端,反序列化时候必须有对应的数据类型,否则就会报错。尤其是自己定义的类。必须远程得有一致的定义。
3、Json
1)是一种轻量级的数据交换格式,基于ECMAScript(w3c制定的JS规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。
2)数据类型
值
双引号引起来的字符串,数值,true和flase,null,对象,数组,这些都是值。
字符串
由双引号包围起来的任意字符的组合,可以有转义字符。
数值:有正负,整数,浮点数。
对象:无序的键值对的集合。
格式:{key1:value1,.....keyn:valuen}
Key必须是一个字符串,需要双引号包围这个字符。
Value可以是任意合法的值。
数组:有序的值的集合
格式:[value1,....valuen]
例子:
2) json模块
Python与json
Python支持少量内建数据类型到json类型的转换。
Python类型 |
Json类型 |
True |
True |
False |
False |
None |
Null |
Str |
String |
Int |
Integer |
Float |
Float |
List |
Array |
Dict |
obiect |
3) 常用的方法
Python 类型 |
Json类型 |
Dumps |
Json编码 |
Dump |
Json编码并写入文件 |
Loads |
Json解码 |
Load |
Json解码,从文件读取数据 |
import json
d = {'name':'tom','age':20,'interest':['music','movie']}
j = json.dumps(d)
print(j)
d1 = json.loads(j)
print(d1)
{"name": "tom", "age": 20, "interest": ["music", "movie"]}
{'name': 'tom', 'age': 20, 'interest': ['music', 'movie']}
一般json编码的数据就很少落地,数据都是通过网络传输。传输的时候要考虑压缩。
本质上来说就是一个文本,就是个字符串。
Json很简单,几乎语言编程都支持json,所以应用范围十分广泛。
4、MessagePack
是一个基于二进制高效的对象化序列类库,可用于跨语言通信。
可以像json那样,在许多种需要之间交换结构对象。
比json更快速也更轻巧。
支持python,ruby,java,C/C++等众多语言。
安装:
Pip install msgpack-python
常用方法
Packb序列化对象,提供了dumps兼容pickle和json
Unpackb反序列化对象,提供了loads来兼容
Pack序列化对象保存到文件对象,提供了dump来兼容
Unpack反序列化对象保存到文件对象,提供了load来兼容。
##
import json
import msgpack
d = {'person':[{'name':'tom','age':18},{'name':'jerry','age':16}],'total':2}
j = json.dumps(d)
m =msgpack.dumps(d)
print('json={},msgpack={}'.format(len(j),len(m)))
print(j.encode(),len(j.encode()))
print(m)
u = msgpack.unpackb(m)
print(type(u),u)
u = msgpack.unpackb(m,encoding='utf-8')
print(type(u),u)
MessagePack简单易用,高效压缩,支持的语言丰富
序列化也是一种很好的选择。
简单易用,高效压缩,支持语言丰富,所以,用它序列化是一种很好的选择。
6、argparse模块
1)一个可执行文件或者脚本都可以接收参数。
ls -l/etc /etc是位置参数 -l 是短选项
如何将参数传递到程序,就使用参数分析模块argparse
1) 参数分类。
参数分为:位置参数,参数放在哪里,就要对应一个参数位置,例如/etc 就是对应的一个参数位置。
选项参数,必须通过前面 - 的短选项或者 --的长选项,然后后面的才算是参数,短选项后面也可以没有参数。
/etc 对应的就是位置参数, -l是选项参数。
3)基本解析
import argparse
parser = argparse.ArgumentParser()
args = parser.parse_args()
parser.print_help()
usage: argparse模块使用.py [-h]
optional arguments:
-h, --help show this help message and exit
Argparse不仅仅做了参数的定义和解析,还自动生成了帮助信息。Usage,可以看到现在定义的参数是否是自己想要的。
4)解析器的参数
参数名称 |
说明 |
Prog |
程序的名字,缺省使用,sys.argv[0] |
add_help |
自动生成解析器增加 - h和--help选项,默认为True |
description |
为程序添加功能描述 |
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
args = parser.parse_args()
parser.print_help()
usage: ls [-h]
list directorycontents
optional arguments:
-h, --help show this help message and exit
2) 位置参数解析器
ls 基本功能解决目录内容的打印。
打印的时候应该制定目录路径,需要的位置参数。
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path')
args = parser.parse_args() #分析参数
parser.print_help() #打印帮助
usage: ls [-h] path
ls: error: the following arguments are required: path
程序等定义为
ls [-h] path
-h为帮助,可有可无
path 为位置参数,必须提供。
6)传参
Parse_args(args=None,namespace=None)
args参数列表,一个可迭代对象,内部会把可迭代对象转换成list,如果为None则使用命令行传入参数,非None则使用args参数的可迭代对象。
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path') #位置参数
args = parser.parse_args(('/etc',)) #分析参数
print(args) #打印名词空间中收集的参数
parser.print_help() #打印帮助
Namespace(path='/etc')
usage: ls [-h] path
list directorycontents
positional arguments:
path
optional arguments:
-h, --help show this help message and exit
Namespace(path='/etc')里面的path参数存储在一个Namespace对象内的属性上,,可以通过Namespace对象属相来访问。args.path
7)非必须位置参数。
必须输入位置参数,否则会报错。
有些时候ls命令不需要输入任何路径就表示列出当前目录的文件列表。
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置参数,可有,可无,缺省值,帮助
args = parser.parse_args() #分析参数
print(args) #打印名词空间中收集的参数
parser.print_help() #打印帮助
Namespace(path='.')
usage: ls [-h] [path]
list directorycontents
positional arguments:
path path help
optional arguments:
-h, --help show this help message and exit
看到path也变成了可选位置参数,没有提供默认值.表示当前的路径。
.help表示帮助文档中这个参数的描述。
.nargs表示这个参数接受结果参数,?表示可有可无,+表示至少一个,*表示任意个,数字表示必须是制定数目个。
.default表示如果不提供该参数,就一直使用这个值,一般和?、*配合,因为他们都可以不提供位置参数,不提供就是使用缺省值。
8)选项参数
-l 的实现:
-a 的实现。长选项同时给出,
import argparse
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置参数,可有,可无,缺省值,帮助
parser.add_argument('-l',action ='store_true',help = 'use a one 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='.')
usage: ls [-h] [-l] [-a] [path]
list directorycontents
positional arguments:
path path help
optional arguments:
-h, --help show this help message and exit
-l use a one listing format
-a, --all show all files,do not ignore entries starting with .
1) ls 业务功能的实现。
上面解决了参数的定义和传参的问题,下面解决业务问题:
(1) .列出所有指定路径的文件,默认是不递归的。
(2) -a显示所有文件,包括隐藏文件。
(3) -l详细列表模式显示。
代码实现:listdirdetail和listdir
import argparse
from pathlib import Path
from datetime import datetime
#获得一个参数解析器
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置参数,可有,可无,缺省值,帮助
parser.add_argument('-l',action ='store_true',help = 'use a one 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() #打印帮助
def listdir(path,all=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'): #不显示隐藏文件
continue
yield i.name
print(list(listdir(args.path)))
#获取文件类型
def _getfiletype(f:path):
# f = Path(path)
if f.is_dir():
return 'd'
elif f.is_block_device():
return 'b'
elif f.is_char_device():
return 'c'
elif f.is_socket():
return 's'
elif f.is_symlink():
return 'l'
else:
return '-'
##显示文件权限等 mode
modelist = dict(zip(range(9),['r','w','x','r','w','x','r','w','x']))
def _getmodestr(mode:int):
m = mode &0o777
mstr = ''
for i in range(8,-1,-1):
if m >>i & 1:
mstr += modelist[8-i]
else:
mstr +='-'
return mstr
def listdirdetail(path,all=False,detail=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t = _setfiletype(i)
mode = _getfiletype(i)+_getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime('%Y %m %d %H:%M:%S')
yield (mode,stat.st_nlink,stat.st_uid,stat.st_gid,stat.st_size,atime,i.name)
for x in listdir(args.path):
print(x)
Mode是整数,八进制描述的权限,最终显示rwx的格式。
modelist = dict(zip(range(9),['r','w','x','r','w','x','r','w','x']))
def _getmodestr(mode:int):
m = mode &0o777
mstr = ''
for i in range(8,-1,-1):
if m >>i & 1:
mstr += modelist[8-i]
else:
mstr +='-'
return mstr
2) 排序
显示的文件按照文件名的升序排序输出。
Sorted(listdir(args.path,detail=True),key=lambda x:x[len(x)-1])
3) 完整代码:
import argparse
from pathlib import Path
from datetime import datetime
#获得一个参数解析器
parser = argparse.ArgumentParser(prog= 'ls',add_help=True,description='list directorycontents')
parser.add_argument('path',nargs='?',default='.',help='path help') #位置参数,可有,可无,缺省值,帮助
parser.add_argument('-l',action ='store_true',help = 'use a one listing format')
parser.add_argument('-a','--all',action ='store_true',help='show all files,do not ignore entries starting with .')
def listdir(path,all=False,detail=False):
def _getfiletype(f: path):
if f.is_dir():
return 'd'
elif f.is_block_device():
return 'b'
elif f.is_char_device():
return 'c'
elif f.is_socket():
return 's'
elif f.is_symlink():
return 'l'
else:
return '-'
modelist = dict(zip(range(9), ['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x']))
def _getmodestr(mode: int):
m = mode & 0o777
mstr = ''
for i in range(8, -1, -1):
if m >> i & 1:
mstr += modelist[8 - i]
else:
mstr += '-'
return mstr
def _listdir(path, all=False, detail=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t = _setfiletype(i)
mode = _getfiletype(i) + _getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime('%Y %m %d %H:%M:%S')
yield (mode, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, atime, i.name)
yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) - 1])
if __name__ == '__main__':
args = parser.parse_args() # 分析参数
print(args) # 打印名词空间中收集的参数
parser.print_help() # 打印帮助
files = listdir(args.path,args.all,args.l)
4) -h的实现
-h ,-human-readable,如果-l存在,-h有效。
import argparse
from pathlib import Path
from datetime import datetime
parser = argparse.ArgumentParser(prog='ls',description='list directory contents',add_help=False)
parser.add_argument('path',nargs='?',default='.',help='path help')
parser.add_argument('-h','--human-readable',action='store_true',help='with -l,print sizes in human readable format')
# args = parser.parse_args() # 分析参数
# print(args) # 打印名词空间中收集的参数
# parser.print_help() # 打印帮助
def listdir(path,all=False,detail=False,human=False):
def _getfiletype(f:path):
"""获取文件的类型"""
if f.is_dir():
return 'd'
elif f.is_block_device():
return 'b'
elif f.is_char_device():
return 'c'
elif f.is_socket():
return 's'
elif f.is_symlink():
return 'l'
elif f.is_fifo():
return 'p'
else:
return '-'
modelist = dict(zip(range(9),['r', 'w', 'x', 'r', 'w', 'x', 'r', 'w', 'x']))
def _getmodest(mode:int):
m =mode & 0o777
mstr = ''
for x in range(8,-1,-1):
if m >> i & 1:
mstr += modelist[8-i]
else:
mstr += '-'
return mstr
def _gethuman(size: int):
units = 'KMGTP'
depth = 0
while size >= 1000:
size = size // 1000
depth += 1
return '{}{}'.format(size, units[depth])
def _listdir(path,all=False,detail=False,human=False):
p =Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
stat = i.stat()
# t = _setfiletype(i)
mode = _getfiletype(i) + _getmodestr(stat.st_mode)
atime = datetime.fromtimestamp(stat.st_atime).strptime('%Y %m %d %H:%M:%S')
yield (mode, stat.st_nlink, stat.st_uid, stat.st_gid, stat.st_size, atime, i.name)
yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) - 1])
if __name__ == '__main__':
args = parser.parse_args() # 分析参数
print(args) # 打印名词空间中收集的参数
parser.print_help() # 打印帮助
files = listdir(args.path,args.all,args.l)
5) 改进mode的模块
使用stat模块
import stat
from pathlib import Path
stat.filemode(Path().stat().st_mode)
6) 最终代码:
import argparse
import stat
from pathlib import Path
from datetime import datetime
parser = argparse.ArgumentParser(prog='ls',description='list directory contents',add_help=False)
parser.add_argument('path',nargs='?',default='.',help='path help')
parser.add_argument('-h','--human-readable',action='store_true',help='with -l,print sizes in human readable format')
parser.add_argument('-l',action ='store_true',help = 'use a one 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() # 打印帮助
def listdir(path,all=False,detail=False,human=False):
def _gethuman(size: int):
units = 'KMGTP'
depth = 0
while size >= 1000:
size = size // 1000
depth += 1
return '{}{}'.format(size, units[depth])
def _listdir(path, all=False, detail=False, human=False):
p = Path(path)
for i in p.iterdir():
if not all and i.name.startswith('.'):
continue
if not detail:
yield (i.name,)
else:
st = i.stat()
# t = _setfiletype(i)
mode = stat.filemode(st.st_mode)
atime = datetime.fromtimestamp(st.st_atime).strptime('%Y %m %d %H:%M:%S')
size = str(st.st_size) if not huam else _gethuman(st.st_size)
yield (mode, st.st_nlink, st.st_uid, st.st_gid, size, atime, i.name)
yield from sorted(_listdir(path, all, detail), key=lambda x: x[len(x) - 1])
if __name__ == '__main__':
args = parser.parse_args() # 分析参数
print(args) # 打印名词空间中收集的参数
parser.print_help() # 打印帮助
files = listdir(args.path, args.all, args.l)