📜  pickle — Python对象序列化

📅  最后修改于: 2022-05-13 01:54:32.253000             🧑  作者: Mango

pickle — Python对象序列化

pickle 模块用于实现用于序列化和反序列化Python对象结构的二进制协议。

  • Pickling:这是一个将Python对象层次结构转换为字节流的过程。
  • Unpickling:它是 Pickling 过程的逆过程,将字节流转换为对象层次结构。

模块接口:

  • dumps() - 调用此函数来序列化对象层次结构。
  • load() - 调用此函数来反序列化数据流。

pickle 模块提供的常量:

  1. pickle.HIGHEST_PROTOCOL
    这是一个整数值,表示可用的最高协议版本。这被认为是传递给函数 dump()、dumps() 的协议值。
  2. pickle.DEFAULT_PROTOCOL
    这是一个整数值,表示用于酸洗的默认协议,其值可能小于最高协议的值。

pickle 模块提供的功能:

  1. pickle.dump(obj,文件,协议 = 无,*,fix_imports = True)
    这个函数相当于 Pickler(file, protocol).dump(obj)。这用于将 obj 的腌制表示写入打开的文件对象文件。
    可选的协议参数是一个整数,告诉pickler 使用给定的协议。支持的协议是 0 到 HIGHEST_PROTOCOL。如果未指定,则默认为 DEFAULT_PROTOCOL。如果指定负数,则选择 HIGHEST_PROTOCOL。
    如果 fix_imports 为真且协议小于 3,pickle 将尝试将新的Python 3 名称映射到Python 2 中使用的旧模块名称,以便Python 2 可以读取 pickle 数据流。
    例子 :
Python3
# Python program to illustrate
# pickle.dump()
import pickle
import io
 
class SimpleObject(object):
 
    def __init__(self, name):
        self.name = name
        l = list(name)
        l.reverse()
        self.name_backwards = ''.join(l)
        return
 
data = []
data.append(SimpleObject('pickle'))
data.append(SimpleObject('cPickle'))
data.append(SimpleObject('last'))
 
# Simulate a file with StringIO
out_s = io.StringIO()
 
# Write to the stream
for o in data:
    print ('WRITING: %s (%s)' % (o.name, o.name_backwards))
    pickle.dump(o, out_s)
    out_s.flush()


Python3
# Python program to illustrate
#Picle.dumps()
import pickle
 
data = [ { 'a':'A', 'b':2, 'c':3.0 } ]
data_string = pickle.dumps(data)
print ('PICKLE:', data_string )


Python3
# Python program to illustrate
# pickle.load()
import pickle
import io
 
class SimpleObject(object):
 
    def __init__(self, name):
        self.name = name
        l = list(name)
        l.reverse()
        self.name_backwards = ''.join(l)
        return
 
data = []
data.append(SimpleObject('pickle'))
data.append(SimpleObject('cPickle'))
data.append(SimpleObject('last'))
 
# Simulate a file with StringIO
out_s = io.StringIO()
 
 
# Write to the stream
for o in data:
    print ('WRITING: %s (%s)' % (o.name, o.name_backwards))
    pickle.dump(o, out_s)
    out_s.flush()
     
     
# Set up a read-able stream
in_s = io.StringIO(out_s.getvalue())
 
# Read the data
while True:
    try:
        o = pickle.load(in_s)
    except EOFError:
        break
    else:
        print ('READ: %s (%s)' % (o.name, o.name_backwards))


Python3
# Python program to illustrate
# pickle.loads()
import pickle
import pprint
 
data1 = [ { 'a':'A', 'b':2, 'c':3.0 } ]
print ('BEFORE:',)
pprint.pprint(data1)
 
data1_string = pickle.dumps(data1)
 
data2 = pickle.loads(data1_string)
print ('AFTER:',)
pprint.pprint(data2)
 
print ('SAME?:', (data1 is data2))
print ('EQUAL?:', (data1 == data2))


Python3
import pickle
 
class TextReader:
    """Print and number lines in a text file."""
  
    def __init__(self, filename):
        self.filename = filename
        self.file = open(filename)
        self.lineno = 0
  
    def readline(self):
        self.lineno + 1
        line = self.file.readline()
        if not line:
            return None
        if line.endswith('\n'):
            line = line[:-1]
        return "%i: %s" % (self.lineno, line)
  
    def __getstate__(self):
        # Copy the object's state from self.__dict__ which contains
        # all our instance attributes. Always use the dict.copy()
        # method to avoid modifying the original state.
        state = self.__dict__.copy()
        # Remove the unpicklable entries.
        del state['file']
        return state
  
    def __setstate__(self, state):
        # Restore instance attributes (i.e., filename and lineno).
        self.__dict__.update(state)
        # Restore the previously opened file's state. To do so, we need to
        # reopen it and read from it until the line count is restored.
        file = open(self.filename)
        for _ in range(self.lineno):
            file.readline()
        # Finally, save the file.
        self.file = file
   
reader = TextReader("Geeksforgeeks.txt")
print(reader.readline())
print(reader.readline())
new_reader = pickle.loads(pickle.dumps(reader))
print(new_reader.readline())


  1. 输出 :
WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)
  1. pickle.dumps(obj,协议 = 无,*,fix_imports = True)
    此函数将对象的腌制表示返回为字节对象。
    例子 :

Python3

# Python program to illustrate
#Picle.dumps()
import pickle
 
data = [ { 'a':'A', 'b':2, 'c':3.0 } ]
data_string = pickle.dumps(data)
print ('PICKLE:', data_string )
  1. 输出 :
PICKLE: (lp0
(dp1
S'a'
p2
S'A'
p3
sS'c'
p4
F3.0
sS'b'
p5
I2
sa.
  1. pickle.load(file, *, fix_imports = True, encoding = “ASCII”, errors = “strict”)
    这个函数相当于 Unpickler(file).load()。此函数用于从打开的文件对象文件中读取腌制对象表示并返回指定的重构对象层次结构。
    例子 :

Python3

# Python program to illustrate
# pickle.load()
import pickle
import io
 
class SimpleObject(object):
 
    def __init__(self, name):
        self.name = name
        l = list(name)
        l.reverse()
        self.name_backwards = ''.join(l)
        return
 
data = []
data.append(SimpleObject('pickle'))
data.append(SimpleObject('cPickle'))
data.append(SimpleObject('last'))
 
# Simulate a file with StringIO
out_s = io.StringIO()
 
 
# Write to the stream
for o in data:
    print ('WRITING: %s (%s)' % (o.name, o.name_backwards))
    pickle.dump(o, out_s)
    out_s.flush()
     
     
# Set up a read-able stream
in_s = io.StringIO(out_s.getvalue())
 
# Read the data
while True:
    try:
        o = pickle.load(in_s)
    except EOFError:
        break
    else:
        print ('READ: %s (%s)' % (o.name, o.name_backwards))
  1. 输出 :
WRITING: pickle (elkcip)
WRITING: cPickle (elkciPc)
WRITING: last (tsal)
READ: pickle (elkcip)
READ: cPickle (elkciPc)
READ: last (tsal)
  1. pickle.loads(bytes_object, *, fix_imports = True, encoding = “ASCII”, errors = “strict”)
    此函数用于从字节对象读取腌制对象表示并返回指定的重构对象层次结构。
    例子 :

Python3

# Python program to illustrate
# pickle.loads()
import pickle
import pprint
 
data1 = [ { 'a':'A', 'b':2, 'c':3.0 } ]
print ('BEFORE:',)
pprint.pprint(data1)
 
data1_string = pickle.dumps(data1)
 
data2 = pickle.loads(data1_string)
print ('AFTER:',)
pprint.pprint(data2)
 
print ('SAME?:', (data1 is data2))
print ('EQUAL?:', (data1 == data2))
  1. 输出 :
BEFORE:[{'a': 'A', 'b': 2, 'c': 3.0}]
AFTER:[{'a': 'A', 'b': 2, 'c': 3.0}]
SAME?: False
EQUAL?: True

pickle 模块提供的异常:

  1. 异常pickle.PickleError
    这个异常继承了Exception。它是酸洗中引发的所有其他异常的基类。
  2. 异常pickle.PicklingError
    此异常继承 PickleError。当 Pickler 遇到不可拾取的对象时,会引发此异常。
  3. 异常pickle.UnpicklingError
    此异常继承 PickleError。当 unpickling 对象时出现数据损坏或安全违规等问题时,会引发此异常。

pickle 模块导出的类:

  1. 类pickle.Pickler(文件,协议=无,*,fix_imports =真)
    这个类需要一个二进制文件来写一个pickle数据流。
    1. dump(obj) -此函数用于将 obj 的腌制表示写入构造函数中给出的打开文件对象。
    2. persistent_id(obj) –如果 persistent_id() 返回 None,则 obj 像往常一样被腌制。默认情况下它什么都不做,并且存在,因此任何子类都可以覆盖它。
    3. Dispatch_table –pickler 对象的调度表是一个映射,其键是类,其值是归约函数。
      默认情况下,pickler 对象没有 dispatch_table 属性,而是使用由 copyreg 模块管理的全局调度表。
      示例:下面的代码创建了一个 pickle.Pickler 实例,其中包含一个专用调度表,该表专门处理 SomeClass 类。
f = io.BytesIO()
p = pickle.Pickler(f)
p.dispatch_table = copyreg.dispatch_table.copy()
p.dispatch_table[SomeClass] = reduce_SomeClass
  1. 快速 -快速模式禁用备忘录的使用并通过不生成多余的 PUT 操作码来加速酸洗过程。
  2. 类pickle.Unpickler(文件,*,fix_imports = True,编码=“ASCII”,错误=“严格”)

    此类采用二进制文件来读取 pickle 数据流。

    1. load() -此函数用于从打开的文件对象文件中读取腌制对象表示并返回指定的重组对象层次结构。
    2. persistent_load(pid) -默认情况下会引发 UnpicklingError。
    3. find_class(module, name) -如果需要,此函数会导入模块并从中返回名为 name 的对象,其中模块和 name 参数是 str 对象。

什么可以腌制和不腌制?
可以腌制以下类型:

  • 无、真和假
  • 整数、浮点数、复数
  • 字符串,字节,字节数组
  • 仅包含可提取对象的元组、列表、集合和字典
  • 在模块顶层定义的函数(使用 def,而不是 lambda)
  • 在模块顶层定义的内置函数
  • 在模块顶层定义的类
  • 此类类的实例,其 __dict__ 或调用 __getstate__() 的结果是可挑选的

酸洗类实例:
本节介绍可用于定义、自定义和控制类实例如何被腌制和解除腌制的一般机制。
不需要额外的代码来使实例可以选择。默认情况下,pickle 将通过自省检索实例的类和属性。
类可以通过提供一种或几种特殊方法来改变默认行为:

  1. object.__getnewargs_ex__()
    此方法规定了在 unpickling 时传递给 __new__() 方法的值。该方法必须返回一对 (args, kwargs),其中 args 是位置参数的元组,而 kwargs 是用于构造对象的命名参数字典。
  2. object.__getnewargs__()
    此方法仅支持正参数。它必须返回一个参数 args 的元组,该元组将在 unpickling 时传递给 __new__() 方法。
  3. object.__getstate__()
    如果这个方法是由类定义的,它会被调用并且返回的对象被pickle作为实例的内容,而不是实例字典的内容。
  4. 对象.__setstate__(状态)
    如果此方法是由类定义的,则以 unpickled 状态调用它。腌制状态必须是一个字典,并且它的项目被分配给新实例的字典。
  5. object.__reduce__()
    __reduce__() 方法不接受任何参数,并且应该返回一个字符串或者最好是一个元组。
  6. object.__reduce_ex__(协议)
    此方法类似于 __reduce__ 方法。它需要一个整数参数。此方法的主要用途是为较旧的Python版本提供向后兼容的 reduce 值。

示例:处理有状态对象
此示例显示如何修改类的酸洗行为。 TextReader 类打开一个文本文件,并在每次调用其 readline() 方法时返回行号和行内容。

  1. 如果对 TextReader 实例进行了腌制,则保存文件对象成员以外的所有属性。
  2. 当实例被 unpickle 时,文件被重新打开,并从最后一个位置继续读取。

Python3

import pickle
 
class TextReader:
    """Print and number lines in a text file."""
  
    def __init__(self, filename):
        self.filename = filename
        self.file = open(filename)
        self.lineno = 0
  
    def readline(self):
        self.lineno + 1
        line = self.file.readline()
        if not line:
            return None
        if line.endswith('\n'):
            line = line[:-1]
        return "%i: %s" % (self.lineno, line)
  
    def __getstate__(self):
        # Copy the object's state from self.__dict__ which contains
        # all our instance attributes. Always use the dict.copy()
        # method to avoid modifying the original state.
        state = self.__dict__.copy()
        # Remove the unpicklable entries.
        del state['file']
        return state
  
    def __setstate__(self, state):
        # Restore instance attributes (i.e., filename and lineno).
        self.__dict__.update(state)
        # Restore the previously opened file's state. To do so, we need to
        # reopen it and read from it until the line count is restored.
        file = open(self.filename)
        for _ in range(self.lineno):
            file.readline()
        # Finally, save the file.
        self.file = file
   
reader = TextReader("Geeksforgeeks.txt")
print(reader.readline())
print(reader.readline())
new_reader = pickle.loads(pickle.dumps(reader))
print(new_reader.readline())

输出 :

0: hi geeks!, this is line 1.
0: This is line 2.
0: hi geeks!, this is line 1.