Python中的序列化和反序列化

为什么要序列化

内存中的字典、列表、集合以及各种对象,如何保存到一个文件中。

设计一套协议,按照某种规则,把内存中的数据保存到文件中,文件是一个个字节序列。所以必须把数据额转换为字节序列,输出到文件,这就是序列化,反之,从文件的字节 序列恢复到内存中,就是反序列化。

 

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)
posted @ 2018-11-12 22:42  Python爱好者666  阅读(28913)  评论(0编辑  收藏  举报