Python pickle序列化对象方法的存储与反序列化行为解析
预期运行结果
代码执行无报错,最终etienne.name的值为etienne..。
背后实现逻辑
pickle对自定义类实例的序列化/反序列化机制和「完整存储对象所有信息」的直觉认知不同,核心规则如下:
- 序列化阶段:pickle不会保存类的代码、类的方法实现,只会存储两类信息:
- 实例所属类的标识(模块路径+类名,这段单脚本场景下就是当前作用域的
Person类名) - 实例的所有实例属性,也就是存在实例
__dict__里的内容,这里序列化时存的就是name = 'etienne'
- 实例所属类的标识(模块路径+类名,这段单脚本场景下就是当前作用域的
- 反序列化阶段:pickle不会自行重建类,而是先到当前运行环境的对应作用域下,查找序列化时记录的类名对应的类,找到后直接创建一个不经过
__init__初始化的空实例,再把之前存好的实例属性直接赋值到这个空实例上,实例能调用的所有方法,全部来自当前环境里查到的这个类的定义。
对应到这段测试代码的执行流程:
- 第一次定义
Person类后创建实例,序列化时只记录了「这是Person类的实例,属性name为'etienne'」,完全没有存储旧版本add_dot加单个点的逻辑。 - 代码重新定义了
Person类,此时当前作用域里的Person已经替换成了add_dot方法会加两个点的新版本。 - 反序列化时pickle查到当前作用域的
Person是新版本,就用这个类创建空实例、还原name属性,后续调用add_dot自然执行新版本的逻辑,给name后缀拼接两个点。
注:如果反序列化时当前环境找不到对应名字的类,会直接抛出
AttributeError异常,这也能侧面证明pickle根本没有存储类的实现代码。
内容的提问来源于stack exchange,提问作者Etienne Herlaut
相关产品推荐
相关产品推荐

