[Python] Python pickle模块学习

概述

Python中提供了三个用于序列化和反序列化的模块:marshal、json和pickle,这里对pickle模块进行总结归纳。

pickle是Python中的一个标准模块,其实现了序列化和反序列化的二进制协议,可以对对象进行序列化和反序列化操作,“Pickling”表示Python对象转换为字节流的过程,这一过程为序列化过程,“Unpickling”和“Pickling”恰好相反,是将字节流转换为Python对象的过程,这一过程也称为反序列化。,但是其缺点是没有加密机制和数字签名,因此安全性差,尽管如此,pickle还是用于处理ad-hoc的理想模式。

优点
  • 使用pickle可以对各种可以pickle的类型进行快速的压缩
缺点
  • 没有安全机制(没有加密机制和数字签名),因此不能对不可信的或为授权的字节流进行反序列化
pickle和json区别
  • 1.json是一种文本序列化格式(它输出unicode文本,虽然大多数时候它被编码为utf-8),而pickle是一种二进制序列化格式;
  • 2.json序列化后的文件具有可读性,而pickle不具有;
  • 3.json广泛用于其他语言汇总,pickle是Python特有的;
  • 4.默认情况下,JSON只能用于Python内置类型的一个子集,并且不包含自定义类; pickle可以用于大量的Python类型。

pickle API

属性

pickle.HIGHEST_PROTOCOL:表示最高可用的pickle协议,在dump()方法和load()方法中作为参数使用,也可以使用在Pickle构造方法中。
pickle.DEFAULT_PROTOCOL:表示默认的pickle协议。

方法

pickle.dump(obj, file, protocol=None, *, fix_imports=True):将pickled的对象写入二进制文件中,和Pickler(file, protocol).dump(obj)方法等价。
pickle.dumps(obj, protocol=None, *, fix_imports=True):将pickled的对象序列化后返回一个byte对象,而不是写入到文件中。
pickle.load(file, *, fix_imports=True, encoding="ASCII", errors="strict"):从打开的二进制文件中中读取一个pickle对象,并返回该对象的重组对象,和Pickler(file).load(obj)方法等价;
pickle.loads(bytes_object, *, fix_imports=True, encoding="ASCII", errors="strict"):从字节流中读取一个pickle对象表示并返回该对象的重组对象;

异常

exception pickle.PickleError:pickling和unpickling时的公共异常类,继承自Exception;
exception pickle.PicklingError:序列化一个unpickabled对象时将抛出,继承自PicklerError;
exception pickle.UnpicklingError:反序列化一个unpickabled对象时将抛出,继承自PicklerError;

class pickle.Pickler(file, protocol=None, *, fix_imports=True):将pickled数据流写入二进制文件中;
class pickle.Unpickler(file, *, fix_imports=True, encoding="ASCII", errors="strict"):从二进制文件中读取pickled数据流。

哪些类型可以picked和unpicked

可以picked的类型:


  • None, True, and False
  • integers, floating point numbers, complex numbers
  • strings, bytes, bytearrays
  • 仅限于包含pickable对象的tuples, lists, sets, dictionaries
  • 在模块顶层定义的函数 (使用 def, lambda函数不行)
  • 在模块顶层定义的内置函数
  • 在模块顶层定义的类
  • 类的__dict__或调用__getstate __()的结果的实例。

1.对函数而言,是通过函数名来pickle的,只有函数名时可pickled的,函数代码、属性都不是可pickled的,因此,如果需要序列化函数或方法,必须导入对应方法所在的模块和对象名。
2.类也通过类名来进行pickle的,所有的类代码和属性都不是可pickled的。

示例

下面对基于上篇文章struct模块处理二进制文件时定义的类Student简单做了修改,通过pickle对其进行序列化和反序列化,代码如下:

import sys
import os
import pickle


class Student:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        assert isinstance(age, int), "age must be integer"
        self.__age = age

    def export_binary(self,filename):
        fh = None
        try:
            fh = open(filename, "wb")
            pickle.dump(self, fh, pickle.HIGHEST_PROTOCOL)
            return True
        except(EnvironmentError, pickle.PicklingError) as err:
            print("{0}: export err:{1}".format(
                os.path.basename(sys.argv[0]), err
            ))
            return False
        finally:
            if fh is not None:
                fh.close()

    def import_binary(self, filename):
        fh = None
        try:
            fh = open(filename, "rb")
            s = pickle.load(fh)
            print(s.name, s.age)   # zhangsan 21
            return True
        except(EnvironmentError,pickle.UnpicklingError) as err:
            print("{0}: export err:{1}".format(
                os.path.basename(sys.argv[0]), err
            ))
            return False
        finally:
            if fh is not None:
                fh.close()


if __name__ == "__main__":
    s1 = Student("zhangsan", 21)
    s2 = Student("Lisi", 23)
    s1.export_binary("s1.bin")
    s1.import_binary("s1.bin")

总结

pickle模块还是比较复杂的,这里仅仅总结了部分内容,以后对剩余内容再进行总结。
参考文档:https://docs.python.org/3/library/pickle.html

你可能感兴趣的:(Python)