使用Pickle序列化对象方法



我正在尝试了解pickle模块的行为。

在我看来,pickle不保存方法,只保存属性。

以下是我对代码的意思:

import pickle
class Person:
def __init__(self, name):
self.name = name
def add_dot(self):
self.name += '.'
etienne = Person('etienne')
pickled = pickle.dumps(etienne)
class Person:
def __init__(self, name):
self.name = name
def add_dot(self):
self.name += '..' 
etienne = pickle.loads(pickled)
etienne.add_dot()

您希望此代码返回什么?

有人能解释我的这种行为吗?

你试过吗?添加行CCD_ 3并运行它返回"0";艾蒂安&";,但更好的问题是为什么

pickle类实例时需要记住的重要一点是,类实例实际上由两部分组成:实例变量(调用myClass.__dict__查看它们的样子)和告诉python您希望如何解释这些数据的源代码。当您在类的实例上调用方法(如etienne.add_dot())时,它会被转换为对类中方法的基本函数调用,同时将实例作为self的参数传入(因此etienne.add_dot()变为Person(etienne))。这种方案被广泛用于OOP,因为当你运行带有大量类实例的程序时,它有助于节省空间,因为每个实例都可以存储实例变量,并在调用了方法时引用相同的源代码。

正如您所注意到的,pickle模块在酸洗类时使用了完全相同的方案,只保存实例变量,而不保存类本身的源代码。来自泡菜文档:

这是故意的,因此您可以修复类中的错误或向类中添加方法,并且仍然加载使用早期版本的类创建的对象。

简单的答案是否定的,你不能pickle方法,但你可以pickle从模块的顶层(使用def,而不是lambda)访问的函数(内置和用户定义的)

Python文档指出,可以进行pickled和unpickled的类型有:

  • 无、真和假
  • 整数、浮点数、复数
  • 字符串、字节、字节数组
  • 仅包含可拾取对象的元组、列表、集合和字典
  • 函数(内置和用户定义),可从模块的顶层访问(使用def,而不是lambda)
  • 可从模块的顶层访问的类
  • 此类实例的__dict__或调用__getstate__()的结果是可拾取的(有关详细信息,请参阅拾取类实例一节)

根据维基百科的定义,序列化为:

数据结构对象状态转换为可以存储的格式(例如,在文件或内存数据中缓冲器)或传输(例如通过计算机网络),以及稍后重建(可能在不同的计算机环境中)。

Pickle模块不是为了序列化方法而构建的。主要目的是序列化属性的状态。然后在取消拾取时实例化对象。由于该方法是类定义的一部分,因此您的代码可以正常工作,但只能用于稍后的类定义。因此CCD_ 10的值最终为";艾蒂安">

在实例的上下文中,保存类定义通常也是不充分和不可取的,因为关于如何使用序列化数据的指令将来可能会更改。