zoukankan      html  css  js  c++  java
  • Python的序列化与反序列化

            Python的序列化与反序列化

                                          作者:尹正杰

    版权声明:原创作品,谢绝转载!否则将追究法律责任。

      序列化和反序列化可以大致分为两类:文本序列化和二进制序列化。比如python提供的pickle库,他就是基于二进制方式的序列化。而json则是文本方式的序列化,需要遵守相应的文件格式。

      由于pickle序列化和发序列化仅仅同版本的Python可以使用(pickle库的序列化在python2,python3也存在不兼容的问题)。因此我们还会学习MessagePack,它是一个基于二进制高效的对象序列化类库,可用于跨语言通信。

    一.序列化概述

    1>.为什么要序列化

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

      如果是自己定义的类的实例,如何保存到一个文件中?

      如何从文件中读取数据,并让他在内存中再次恢复成自己对应的类的实例?

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

      反之,从文件的字节序列恢复到内存并且还要原来的类型,就是反序列化。

    2>. 序列化相关术语

    serialization
      将内存中对象存储下来,把它变成一个个字节。
    
    deserialization
      将文件的一个个字节恢复成内存中对象。

    序列化保存到文件就是持久化。

    可以将数据序列化后持久化,或者网络传输;也可以将从文件中或者网络接受到的字节序列反序列化。Python提供了pickle库,它是一种基于二进制方式的序列化。

    3>.序列化应用

      一般来说,本地序列化的情况,应用较少。大多数场景都应用在网络传输中。

      将数据序列化后通过网络传输到远程节点,远程服务器上的服务将接收的数据反序列化后,就可以使用了。

      但是,要注意一点,远程接收端,反序列化时必须有对应的数据类型,否则就会报错。尤其是自定义类,必须远程得有一致的定义。

      现在,大多数项目,都不是单机的,也不是单服务的,需要多个程序之间配合。需要通过网络将数据传送到其它节点上去,这就需要大量的序列化,反序列化过程。

      但是,问题是Python程序之间可以使用pickle解决序列化,反序列化,,如果是跨平台,跨语言,跨协议pickle就不太适合了,就需要公共的协议。例如XML,JSON,PROTOCOL BUFFER等。

      不同的协议,效率不同,学习曲线不同,适用不同场景,要根据不同的情况分析选型。

    二.pikcle模块

    1>.方法说明

    dumps:
      对象序列化为bytes对象,一般用于处理网络传输的数据。
    dump:   对象序列化到文件对象,比如存入本地文件。
    loads:
      从bytes对象反序列化,一般用于处理网络接受的数据。 load:
      对象发序列化,从文件读取数据。

    2>.序列化和反序列化基础数据类型

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import pickle
     7 
     8 file_name = r"E:	emp	estser.txt"
     9 
    10 s1 = 99
    11 s2 = 'c'
    12 s3 = list("123")
    13 s4 = {"a":1,"b":"abc","c":[1,2,3]}
    14 
    15 #序列化
    16 with open(file_name,"wb") as f:
    17     pickle.dump(s1,f)
    18     pickle.dump(s2,f)
    19     pickle.dump(s3,f)
    20     pickle.dump(s4,f)
    21 
    22 
    23 #反序列化
    24 with open(file_name,"rb") as f:
    25     print(f.read(),f.seek(0))
    26     for i in range(4):
    27         x = pickle.load(f)
    28         print(x,type(x))
    29 
    30 
    31 
    32 #以上代码执行结果如下:
    33 b'x80x03Kc.x80x03Xx01x00x00x00cqx00.x80x03]qx00(Xx01x00x00x001qx01Xx01x00x00x002qx02Xx01x00x00x003qx03e.x80x03}qx00(Xx01x00x00x00aqx01Kx01Xx01x00x00x00bqx02Xx03x00x00x00abcqx03Xx01x00x00x00cqx04]qx05(Kx01Kx02Kx03eu.' 0
    34 99 <class 'int'>
    35 c <class 'str'>
    36 ['1', '2', '3'] <class 'list'>
    37 {'a': 1, 'b': 'abc', 'c': [1, 2, 3]} <class 'dict'>

    3>.序列化和反序列化对象

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import pickle
     7 
     8 file_name = r"E:	emp	estser.txt"
     9 
    10 #定义对象
    11 class Person:
    12     def __init__(self,name,age=18):
    13         self.__name = name
    14         self.__age = age
    15 
    16     @property
    17     def name(self):
    18         return self.__name
    19 
    20     @name.setter
    21     def name(self,name):
    22         self.__name = name
    23 
    24     def getage(self):
    25         return self.__age
    26 
    27     def setage(self,age):
    28         self.__age = age
    29 
    30     age = property(fget=getage,fset=setage,doc="age property")
    31 
    32     def __repr__(self):
    33         return "{} 今年已经 {} 岁啦!".format(self.__name,self.__age)
    34 
    35 
    36 p1 = Person("Yinzhengjie",20)
    37 
    38 p1.age = 27
    39 
    40 #序列化
    41 ser = pickle.dumps(p1)
    42 print("ser = {}".format(ser))
    43 
    44 #反序列化
    45 p2 = pickle.loads(ser)
    46 print(type(p2))
    47 print(p2)
    48 
    49 
    50 
    51 #以上代码执行结果如下:
    52 ser = b'x80x03c__main__
    Person
    qx00)x81qx01}qx02(X
    x00x00x00_Person__nameqx03Xx0bx00x00x00Yinzhengjieqx04Xx0cx00x00x00_Person__ageqx05Kx1bub.'
    53 <class '__main__.Person'>
    54 Yinzhengjie 今年已经 27 岁啦!

    三.json模块

    1>.Json概述

      JSON(JavaScript Object Notation,JS对象标记)是一种轻量级的数据交换格式。它基于ECMAScript(w3c组织制定的JS规范)的一个子集,采用完全独立与编程语言的文本格式来存储和表示数据。
    
      一般来说,json编码的数据很少落地,数据都是通过网络传输,传输的时候,需考虑压缩它。本质上来说它就是个文本,就是个字符串。

      json很简单,几乎所有编程都支持Json,所以应用范围十分广泛。
      官方网址请参考:http:
    //json.org/。

    2>.Json数据类型

    值:
      双引号引起来的字符串,数值,true和false,null,对象,数组,这些都是值。
    字符串:
      由双引号包围起来的任意字符的组合,可以有转义字符。

    数值:
      有正负,有整数,浮点数。

    对象:
      无序的键值对的集合。
      格式:{key1:value1,...keyn:valulen}
      key必须是一个字符串,需要双引号包围这个字符串。
      value可以是任意合法的值。

    数组:
      有序的值和集合。
      格式:[val1,...valn]

    案例如下:
    {
      "person":[
        {
          "name":"jason",
          "age":18
        },
        {
          "name":"yinzhengjie"
          "age":16
        }
      ],
      "total":2
    }

    3>.Python与Json

    Python支持少量内建数据类型到Json类型的转换,大致如下:
      Python类型          Json类型
        True            true
        False            false
        None            null
        str             string
        int             integer
        float            float
        list             array
        dict             object

    4>.json模块应用案例

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import json
     7 
     8 src = {'name':'Jason','age':20,'interest':('music','movie'),'class':['python']}
     9 
    10 
    11 json_ser = json.dumps(src)              #进行json编码
    12 print(json_ser,type(json_ser))          #注意引号,括号的变化,数据类型的变化。
    13 
    14 dest = json.loads(json_ser)
    15 print(dest)
    16 print(id(src),id(dest))
    17 
    18 
    19 
    20 #以上代码执行结果如下:
    21 {"name": "Jason", "age": 20, "interest": ["music", "movie"], "class": ["python"]} <class 'str'>
    22 {'name': 'Jason', 'age': 20, 'interest': ['music', 'movie'], 'class': ['python']}
    23 2114747181640 2114747436952

    三.MessagePack模块

    1>.MessagePack概述

      MessagePack是一个基于二进制高效的对象序列化类库,可用于跨语言通信。

      它可以像JSON那样,在许多种语言之间交换结构对象。

      但是它比JSON更快速也更轻巧。

      支持Python,Ruby,Java,C/C++等众多语言。宣称比Google Protocol Buffers还要快4倍(这话建议大家听听就好,要以实际测试为准)。
      
      兼容json和pickle。

    2>.MessagePack安装

    messagePack官网地址:https://msgpack.org/
    
    安装messagePack方式:
        C:Usersyinzhengjie>pip install msgpack
        Collecting msgpack
          Downloading https://files.pythonhosted.org/packages/41/0a/49b522c5b23006d60669ec8dc97558e91880673e170108e0e9e21fc452e3/msgpack-0.6.2-cp37-cp37m-win_amd64.whl (68kB)
            100% |████████████████████████████████| 71kB 112kB/s
        Installing collected packages: msgpack
        Successfully installed msgpack-0.6.2
    
        C:Usersyinzhengjie>

    3>. 常用方法

      packb序列化对象。提供了dumps来兼容pickle和json。
      unpackb反序列化对象。提供了loads来兼容。
    
      pack序列化对象保存到文件对象。提供了dump来兼容。
      unpack反序列化对象保存到文件对象。提供红了load来兼容。

      上面的内容了解一下即可,咱们生产环境中还是只用dump(s)和load(s)方法来进行序列化和反序列化,没有必要记得太多,反而浪费脑细胞~嘿嘿嘿。

    4>.对比pickle,json和messagePack的序列化字节大小

     1 #!/usr/bin/env python
     2 #_*_conding:utf-8_*_
     3 #@author :yinzhengjie
     4 #blog:http://www.cnblogs.com/yinzhengjie
     5 
     6 import pickle
     7 import json
     8 import msgpack
     9 
    10 
    11 #导入模块,都是标识符
    12 methods = (pickle,json,msgpack)
    13 
    14 src = {'person':[
    15                     {'name':'Jason','age':18,'hobby':('movie','music','Mountain climbing')},
    16                     {'name':'YinZhengjie','age':20,'hobby':('Basketball','ping-pong','Blogging')}
    17                 ],
    18         'total':2
    19        }
    20 
    21 #进行序列化操作
    22 for method in methods:
    23     s1 = method.dumps(src)
    24     if method == json:          #我们这里仅对json格式文件做一个简单的压缩处理,但生产环境建议不要这样用,因为这样写逻辑并不严谨。
    25         s1 = s1.replace(' ','')
    26     print(method.__name__,type(s1),len(s1),s1)
    27 
    28 
    29 print("*" * 20 + "我是分割线" + "*" * 20)
    30 
    31 #进行反序列话操作
    32 # s2 = msgpack.loads(s1,encoding="utf8")        #这个方法不推荐使用,使用后会抛出"DeprecationWarning: encoding is deprecated, Use raw=False instead."的警告信息哟~
    33 # print(type(s2),s2)
    34 s3 = msgpack.loads(s1,raw=False)                #官方推荐使用"raw=False"的方式
    35 print(type(s3),s3)
    36 
    37 
    38 
    39 
    40 #以上代码执行结果如下:
    41 pickle <class 'bytes'> 225 b'x80x03}qx00(Xx06x00x00x00personqx01]qx02(}qx03(Xx04x00x00x00nameqx04Xx05x00x00x00Jasonqx05Xx03x00x00x00ageqx06Kx12Xx05x00x00x00hobbyqx07Xx05x00x00x00movieqx08Xx05x00x00x00musicq	Xx11x00x00x00Mountain climbingq
    x87qx0bu}qx0c(hx04Xx0bx00x00x00YinZhengjieq
    hx06Kx14hx07X
    x00x00x00Basketballqx0eX	x00x00x00ping-pongqx0fXx08x00x00x00Bloggingqx10x87qx11ueXx05x00x00x00totalqx12Kx02u.'
    42 json <class 'str'> 171 {"person":[{"name":"Jason","age":18,"hobby":["movie","music","Mountainclimbing"]},{"name":"YinZhengjie","age":20,"hobby":["Basketball","ping-pong","Blogging"]}],"total":2}
    43 msgpack <class 'bytes'> 130 b'x82xa6personx92x83xa4namexa5Jasonxa3agex12xa5hobbyx93xa5moviexa5musicxb1Mountain climbingx83xa4namexabYinZhengjiexa3agex14xa5hobbyx93xaaBasketballxa9ping-pongxa8Bloggingxa5totalx02'
    44 ********************我是分割线********************
    45 <class 'dict'> {'person': [{'name': 'Jason', 'age': 18, 'hobby': ['movie', 'music', 'Mountain climbing']}, {'name': 'YinZhengjie', 'age': 20, 'hobby': ['Basketball', 'ping-pong', 'Blogging']}], 'total': 2}

    5>.总结

      MessagePack简单易用,高效压缩,支持语言丰富。所以,用它序列化也是一种很好的选择。Python很大大名鼎鼎的库都是用了msgpack。

      上例中,之所以pickle比json序列化的结果还要大,原因主要是pickle要解决所有python数据类型的序列化,要记录各种数据类型包括自定义的类。而json只需要支持少数几种类型,所以就可以很简单,都不需要类型的描述字符。但大多数情况下,我们序列化的数据都是这些简单的类型。
  • 相关阅读:
    设计模式------命令模式
    设计模式------中介者模式
    重置元素的CSS样式
    正则替换标签内的字符串
    Web移动端Fixed布局的解决方案
    弹窗滚动,禁止底部滚动
    css3 模拟动态加载图标
    利用滚动条进行移动端水平滑动
    滚动加载
    搭建本地服务器调试移动端页面
  • 原文地址:https://www.cnblogs.com/yinzhengjie/p/11149063.html
Copyright © 2011-2022 走看看