You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python 3中__getinitargs__的替代:反序列化时如何调用__init__

在Python 3中反序列化时调用__init__的可行方案

你说得没错——Python 3里所有类都是新式类,__getinitargs__确实被彻底忽略了,而__getnewargs__只能给__new__传参,没办法直接触发__init__执行。针对这个问题,我整理了几个靠谱的解决办法,一个个给你说:

方案1:用__reduce__自定义反序列化逻辑

__reduce__是pickle模块处理对象序列化/反序列化的核心方法,我们可以通过它直接指定反序列化时调用类的构造函数。

修改你的代码如下:

import pickle

class Car:
    def __init__(self, model, number):
        self.model = model
        self.number = number
        print("constructed with", model, number)
        # many other things to do

    def __reduce__(self):
        # 返回元组:(构造函数, 构造参数, 状态)
        # 这里构造函数就是Car类本身,参数对应__init__的入参
        return (Car, (self.model, self.number), None)

c = Car("toyota", 1234)
d = pickle.loads(pickle.dumps(c))
print("reconstructed with", d.model, d.number)

运行后Python 3会输出:

constructed with toyota 1234
constructed with toyota 1234
reconstructed with toyota 1234

完全符合你想要的效果——反序列化时会正常调用__init__,参数也能正确传递。

方案2:结合__getnewargs_ex__和手动调用__init__

如果不想重写__reduce__,也可以用__getnewargs_ex__给__new__传参,再在__new__里手动触发__init__。这个方法适合对__reduce__逻辑不太熟悉的场景:

import pickle

class Car:
    def __init__(self, model, number):
        self.model = model
        self.number = number
        print("constructed with", model, number)
        # many other things to do

    def __getnewargs_ex__(self):
        # 返回(位置参数元组, 关键字参数字典)
        return ((), {"model": self.model, "number": self.number})

    def __new__(cls, *args, **kwargs):
        # 创建实例对象
        instance = super().__new__(cls)
        # 手动调用__init__完成初始化
        instance.__init__(*args, **kwargs)
        return instance

c = Car("toyota", 1234)
d = pickle.loads(pickle.dumps(c))
print("reconstructed with", d.model, d.number)

这个方案也能达到相同效果,不过要注意:如果你的类继承了内置不可变类型(比如str、tuple),__new__的逻辑可能需要调整,但普通自定义类完全适用。

方案3:在__setstate__里手动触发__init__

如果你的需求只是让反序列化后的对象拥有正确属性,且不排斥手动调用__init__,也可以在__setstate__里直接执行初始化逻辑:

import pickle

class Car:
    def __init__(self, model, number):
        self.model = model
        self.number = number
        print("constructed with", model, number)
        # many other things to do

    def __getstate__(self):
        # 保存构造所需的参数
        return {"model": self.model, "number": self.number}

    def __setstate__(self, state):
        # 直接调用__init__完成初始化
        self.__init__(state["model"], state["number"])

c = Car("toyota", 1234)
d = pickle.loads(pickle.dumps(c))
print("reconstructed with", d.model, d.number)

这个方法逻辑直观,适合简单场景,也能正常触发__init__里的所有逻辑。

补充:为什么Python 2的代码在Python 3里失效?

Python 2里老式类和新式类的pickle机制不同,__getinitargs__是专门为老式类设计的初始化参数传递方法。而Python 3统一使用新式类后,pickle的序列化逻辑改成了优先依赖__reduce__、__getnewargs__等方法,__getinitargs__就被直接忽略了,这也是你看到属性未初始化报错的原因。

内容的提问来源于stack exchange,提问作者pevogam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:35:39