Python3 pickle对象串行化代码实例解析

1.pickle对象串行化

pickle模块实现了一个算法可以将任意的Python对象转换为一系列字节。这个过程也被称为串行化对象。可以传输或存储表示对象的字节流,然后再重新构造来创建有相同性质的新对象。

1.1 编码和解码字符串中的数据

第一个例子使用dumps()将一个数据结构编码为一个字符串,然后把这个字符串打印到控制台。它使用了一个完全由内置类型构成的数据结构。任何类的实例都可以pickled,如后面的例子所示。

import pickle
import pprint
data = [{'a': 'A', 'b': 2, 'c': 3.0}]
print('DATA:', end=' ')
pprint.pprint(data)
data_string = pickle.dumps(data)
print('PICKLE: {!r}'.format(data_string))

默认的,pickle将以一种二进制格式写入,在Python 3程序之间共享时这种格式兼容性最好。

数据串行化后,可以写到一个文件、套接字、管道或者其他位置。之后可以读取这个文件,将数据解除pickled,以便用同样的值构造一个新对象。

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

新构造的对象等于原来的对象,但并不是同一个对象。

1.2 处理流

除了dumps()和loads(),pickle还提供了一些便利函数来处理类似文件的流。可以向一个流写多个对象,然后从流读取这些对象,而无须事先知道要写多少个对象或者这些对象多大。

import io
import pickle
class SimpleObject:
  def __init__(self, name):
    self.name = name
    self.name_backwards = name[::-1]
    return
data = []
data.append(SimpleObject('pickle'))
data.append(SimpleObject('preserve'))
data.append(SimpleObject('last'))
# Simulate a file.
out_s = io.BytesIO()
# Write to the stream
for o in data:
  print('WRITING : {} ({})'.format(o.name, o.name_backwards))
  pickle.dump(o, out_s)
  out_s.flush()
# Set up a read-able stream
in_s = io.BytesIO(out_s.getvalue())
# Read the data
while True:
  try:
    o = pickle.load(in_s)
  except EOFError:
    break
  else:
    print('READ  : {} ({})'.format(
      o.name, o.name_backwards))

这个例子使用两个BytesIO缓冲区来模拟流。第一个缓冲区接收pickled的对象,它的值被填入第二个缓冲区,load()读取这个缓冲区。简单的数据库格式也可以使用pickle来存储对象。shelve模块就是这样一个实现。

除了存储数据,pickle对于进程间通信也很方便。例如,os.fork()和os.pipe()可以用来建立工作进程,从一个管道读取作业指令,并把结果写至另一个管道。管理工作线程池以及发送作业和接收响应的核心代码可以重用,因为作业和响应对象不必基于一个特定的类。使用管道或套接字时,在转储各个对象之后不要忘记刷新输出,以便将数据通过连接推送到另一端。参见multiprocessing模块来了解一个可重用的工作线程池管理器。

1.3 重构对象的问题

处理定制类时,pickled的类必须出现在读取pickle的进程所在的命名空间里。只会pickled这个实例的数据,而不是类定义。类名用于查找构造函数,以便在解除pickled时参见新对象。下面这个例子将一个类的实例写至一个文件。

import pickleclass SimpleObject:
  def __init__(self, name):
    self.name = name
    l = list(name)
    l.reverse()
    self.name_backwards = ''.join(l)
if __name__ == '__main__':
  data = []
  data.append(SimpleObject('pickle'))
  data.append(SimpleObject('preserve'))
  data.append(SimpleObject('last'))
  with open('Test.py', 'wb') as out_s:
    for o in data:
      print('WRITING: {} ({})'.format(
        o.name, o.name_backwards))
      pickle.dump(o, out_s)

运行这个脚本时,会根据作为命令行参数给定的名字来创建一个文件。

通过简单的尝试加载而得到的pickled对象将会失败。

import pickle
with open('Test.py', 'rb') as in_s:
  while True:
    try:
      o = pickle.load(in_s)
    except EOFError:
      break
    else:
      print('READ: {} ({})'.format(
        o.name, o.name_backwards))

这个版本失败的原因在于并没有SimpleObject类。

修正后的版本从原脚本导入了SimpleObject,这一次运行会成功。在导入列表的最后增加了import语句后,现在脚本就能找到这个类并构造对象了。

from demo import SimpleObject

现在允许修改后的脚本会生成期望的结果。

1.4Unpicklable的对象

并不是所有对象都是可pickled的。套接字、文件句柄、数据库连接以及其他运行时状态依赖于操作系统或其他进程的对象,其可能无法用一种有意义的方式保存。如果对象包含不可pickled的属性,则可以定义__getstate__()和__setstate__()来返回所pickled实例的状态的一个子集。

__getstate__()方法必须返回一个对象,其中包含所pickled对象的内部状态。表示状态的一种便利方式是使用字典,不过值可以是任意的可pickled对象。保存状态,然后再从pickle加载对象时将所保存的状态传入__setstate__()。

import pickle
class State:
  def __init__(self, name):
    self.name = name
  def __repr__(self):
    return 'State({!r})'.format(self.__dict__)
class MyClass:
  def __init__(self, name):
    print('MyClass.__init__({})'.format(name))
    self._set_name(name)
  def _set_name(self, name):
    self.name = name
    self.computed = name[::-1]
  def __repr__(self):
    return 'MyClass({!r}) (computed={!r})'.format(
      self.name, self.computed)
  def __getstate__(self):
    state = State(self.name)
    print('__getstate__ -> {!r}'.format(state))
    return state
  def __setstate__(self, state):
    print('__setstate__({!r})'.format(state))
    self._set_name(state.name)
inst = MyClass('name here')
print('Before:', inst)
dumped = pickle.dumps(inst)
reloaded = pickle.loads(dumped)
print('After:', reloaded)

这个例子使用了一个单独的State对象来保存MyClass的内部状态。从pickle加载MyClass的一个实例时,会向__setstate__()传入一个State实例,用来初始化这个对象。

1.5 循环引用

pickle协议会自动处理对象之间的循环引用,所以复杂数据结构不需要任何特殊的处理。

import pickle
class Node:
  """A simple digraph
  """
  def __init__(self, name):
    self.name = name
    self.connections = []
  def add_edge(self, node):
    "Create an edge between this node and the other."
    self.connections.append(node)
  def __iter__(self):
    return iter(self.connections)
def preorder_traversal(root, seen=None, parent=None):
  """Generator function to yield the edges in a graph.
  """
  if seen is None:
    seen = set()
  yield (parent, root)
  if root in seen:
    return
  seen.add(root)
  for node in root:
    recurse = preorder_traversal(node, seen, root)
    for parent, subnode in recurse:
      yield (parent, subnode)
def show_edges(root):
  "Print all the edges in the graph."
  for parent, child in preorder_traversal(root):
    if not parent:
      continue
    print('{:>5} -> {:>2} ({})'.format(
      parent.name, child.name, id(child)))
# Set up the nodes.
root = Node('root')
a = Node('a')
b = Node('b')
c = Node('c')
# Add edges between them.
root.add_edge(a)
root.add_edge(b)
a.add_edge(b)
b.add_edge(a)
b.add_edge(c)
a.add_edge(a)
print('ORIGINAL GRAPH:')
show_edges(root)
# Pickle and unpickle the graph to create
# a new set of nodes.
dumped = pickle.dumps(root)
reloaded = pickle.loads(dumped)
print('\nRELOADED GRAPH:')
show_edges(reloaded)

重新加载的节点并不是同一个对象,但保持了节点之间的关系,而且如果对象有多个引用,那么只会重新加载这个对象的一个副本。要验证这两点,可以在通过pickle传递节点之前和之后检查节点的id()值。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 解决python3读取Python2存储的pickle文件问题

    我在使用python3.5处理一个序列化文件xxx.pk,不过这个.pk文件是我在python2.7里面存储的,当我用python3读取的时候就会报如下的错误. import pickle picklefile=open('2ohsumed_wmd_d.pk','rb') data=pickle.load(picklefile) print (data) UnicodeDecodeError: 'ascii' codec can't decode byte 0xa0 in position 11

  • Python3.5 Json与pickle实现数据序列化与反序列化操作示例

    本文实例讲述了Python3.5 Json与pickle实现数据序列化与反序列化操作.分享给大家供大家参考,具体如下: 1.Json:不同语言之间进行数据交互. (1)JSON数据序列化:dumps() JSON数据是一种轻量级的数据交换格式,序列化:将内存数据对象变成字符串. #!/usr/bin/env python # -*- coding:utf-8 -*- # Author:ZhengzhengLiu import json info = { "name":"liu

  • 用python3读取python2的pickle数据方式

    问题一:TypeError: a bytes-like object is required, not 'str' 解决:该问题属于Python3和Python2的字符串兼容问题,数据文件是在Python2下序列化的,使用Python3读取时,需要将'str'转化为'bytes'. picklefile=open('XXX.pkl','r') class StrToBytes: def __init__(self, fileobj): self.fileobj = fileobj def rea

  • Python3 pickle模块的使用方法详细介绍

    pickle模块特点 1.只能在python中使用,只支持python的基本数据类型. 2.可以处理复杂的序列化语法.(例如自定义的类的方法,游戏的存档等) 3.序列化的时候,只是序列化了整个序列对象,而不是内存地址. pickle: 用于python特有的类型和python的数据类型间进行转换,pickle提供四个功能:dumps,dump,loads,load pickle可以存储什么类型的数据呢? 所有python支持的原生类型:布尔值,整数,浮点数,复数,字符串,字节,None. 由任何

  • python3.6使用pickle序列化class的方法

    如下所示: from library.connecter.database.mongo import Op_Mongo a = pickle.dumps(Op_Mongo) #序列化 b = pickle.loads(a) #反序列化 以上这篇python3.6使用pickle序列化class的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们.

  • 详解Python3 pickle模块用法

    pickle(python3.x)和cPickle(python2.x的模块)相当于java的序列化和反序列化操作. 常采用下面的方式使用: import pickle pickle.dump(obj,f) pickle.dumps(obj,f) pickle.load(f) pickle.loads(f) 使用pickle模块你可以把Python对象直接保存到文件,而不需要把他们转化为字符串,也不用底层的文件访问操作把它们写入到一个二进制文件里. pickle模块会创建一个python语言专用

  • Python3 pickle对象串行化代码实例解析

    1.pickle对象串行化 pickle模块实现了一个算法可以将任意的Python对象转换为一系列字节.这个过程也被称为串行化对象.可以传输或存储表示对象的字节流,然后再重新构造来创建有相同性质的新对象. 1.1 编码和解码字符串中的数据 第一个例子使用dumps()将一个数据结构编码为一个字符串,然后把这个字符串打印到控制台.它使用了一个完全由内置类型构成的数据结构.任何类的实例都可以pickled,如后面的例子所示. import pickle import pprint data = [{

  • 第十三节--对象串行化

    /* +-------------------------------------------------------------------------------+ | = 本文为Haohappy读<<Core PHP Programming>>  | = 中Classes and Objects一章的笔记  | = 翻译为主+个人心得  | = 为避免可能发生的不必要的麻烦请勿转载,谢谢  | = 欢迎批评指正,希望和所有PHP爱好者共同进步!  | = PHP5研究中心: 

  • Java并发之串行线程池实例解析

    前言 做Android的这两年时间,通过研究Android源码,也会Java并发处理多线程有了自己的一些理解. 那么问题来了,如何实现一个串行的线程池呢? 思路 何为串行线程池呢? 也就是说,我们的Runnable对象应该有个排队的机制,它们顺序从队列尾部进入,并且从队列头部选择Runnable进行执行. 既然我们有了思路,那我们就考虑一下所需要的数据结构? 既然是从队列尾部插入Runnable对象,从队列头部执行Runnable对象,我们自然需要一个队列.Java的SDK已经给我们提供了很好的

  • 利用XMLSerializer将对象串行化到XML

    微软已经意识到串行化数据的重要性,因此在.NET框架中包含了命名空间System.Runtime.Serialization和System.Xml.Serialization以提供串行化功能,为用户自己编写串行化方法提供了一个框架.System.Xml.Serialization命名空间提供了将一个对象串行化为XML格式的基本方法.下面我们来看看如何使用这种方法. XML的魅力 串行化XML是指为了方便存储或传输,把一个对象的公共的域和属性保存为一种串行格式(这里是XML格式)的过程.非串行化则

  • 第十三节 对象串行化 [13]

    串行化可以把变量包括对象,转化成连续bytes数据. 你可以将串行化后的变量存在一个文件里或在网络上传输. 然后再反串行化还原为原来的数据. 你在反串行化类的对象之前定义的类,PHP可以成功地存储其对象的属性和方法. 有时你可能需要一个对象在反串行化后立即执行. 为了这样的目的,PHP会自动寻找__sleep和__wakeup方法. 当一个对象被串行化,PHP会调用__sleep方法(如果存在的话). 在反串行化一个对象后,PHP 会调用__wakeup方法. 这两个方法都不接受参数. __sl

  • php面向对象全攻略 (十六) 对象的串行化

    把对象串行化 有时候需要把一个对象在网络上传输,为了方便传输,可以把整个对象转化为二进制串, 等到达另一端时,再还原为原来的对象,这个过程称之为串行化,就像我们现在想把一辆汽 车通过轮船运到美国去,因为汽车的体积比较大,我们可以把汽车拆开成小的部件,然后我们把这些部件通过轮般运到美国去,到了美国再把这些部件组装回汽车. 有两种情况我们必须把对象串行化,第一种情况就是把一个对象在网络中传输的时候要 将对象串行化,第二种情况就是把对象写入文件或是数据库的时候用到串行化. 串行化有两个过程,一个是串行

  • 详解PHP对象的串行化与反串行化

    什么时候使用串行化? 在网络中传输对象的时候 向数据库中保存文件的时候 今天我们要提到四个函数 全部串行化 1.serialize(对象名) 将指定的类对象串行化 $str=serialize($per) //将per对象串行化,结果返回给$str 2.unserialize(串行化后的返回值) 返回结果是对象 $per=unserialize($str); 局部串行化 3.__sleep() 串行化某对象的部分属性. 4.__wakeup()反串行化时,初始化(其实是修改)对象内容 前两个的使

  • PHP串行化与反串行化实例分析

    本文实例讲述了PHP串行化与反串行化.分享给大家供大家参考,具体如下: 对象也是一种在内存中存储的数据类型,他的寿命通常随着生成该对象的程序的终止而终止.有时候可能需要把对象的状态保存下来,需要时再将其回复.串行化是把每个对象转化为二进制字符串. <?php class Person { var $name; var $sex; var $age; function __construct($name = "", $sex = "男", $age = 22)

  • PHP中的串行化变量和序列化对象

    串行化大概就是把一些变量转化成为字符串的字节流的形式,这样比较容易传输.存储.当然,关是传输存储没有什么,关键是变成串的形式以后还能够转化回来,而且能够保持原来数据的结构. 在PHP中有多串行化处理的函数:serialize(),该函数把任何变量值(除了资源变量)转化为字符串的形式,可以把字符串保存到文件里,或者注册为Session,乃至于使用curl来模拟GET/POST来传输变量,达到RPC的效果. 如果要将串行化的变量转化成PHP原始的变量值,那么可以使用unserialize()函数.

  • python3读取csv文件任意行列代码实例

    这篇文章主要介绍了python3读取csv文件任意行列代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 读取每一行 reader = csv.reader(f) 此时reader返回的值是csv文件中每行的列表,将每行读取的值作为列表返回 #读取每一行 filename='D:\\file_information1.csv' import csv with open(filename,newline = '',encoding = 'ut

随机推荐