【问题标题】:Python 3 alternatives for __getinitargs____getinitargs__ 的 Python 3 替代方案
【发布时间】:2018-05-12 16:06:31
【问题描述】:

在 Python 3 的 unpickling 期间,是否有足够短的方法来调用类的 __init__ 构造函数?通常的方法是使用__getinitargs__ 像这样

from __future__ import print_function
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):
        # intentionally returns None
        pass

    def __setstate__(self, state):
        pass

    def __getinitargs__(self):
        # save some information when pickling
        # (will be passed to the constructor upon unpickling)
        return self.model, self.number

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

但是,__getinitargs__ 在新样式类中将被忽略,在 Python 3+ 中,所有类只能是新样式类。有__getnewargs__,但它只会将参数传递给不一样的__new__ 类方法。上述说明性示例的 python 2 调用将导致

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

虽然 python 3 调用会出错

>> constructed with toyota 1234
Traceback (most recent call last):
  File "test.py", line 26, in <module>
    print("reconstructed with", d.model, d.number)
AttributeError: 'Car' object has no attribute 'model'

并忽略__getinitargs__ 方法。

我认为 Python 3 在这方面不会轻易退步,所以希望我遗漏了一些明显的东西。

编辑:将__getinitargs__ 替换为__getnewargs__ 并不能解决问题。

【问题讨论】:

  • 为什么首先需要提供__getinitargs__?您可以在此处删除 __getstate____setstate____getinitargs__ 方法,它会正常工作
  • 这是一个更复杂对象的简化示例。该示例的重点是说明python 2中通常使用的方法。

标签: python python-3.x pickle


【解决方案1】:

如果您希望pickle 通过调用Car(self.model, self.number) 来解开您的对象,则通过__init__ 进行初始化,就像对Car 的正常调用一样,然后在__reduce__ method 中告诉它这样做:

def __reduce__(self):
    return (Car, (self.model, self.number))

Demo.

【讨论】:

  • 工作出色 - 谢谢!我只是添加了类似的行以使代码可测试,但您的演示更加完整。我希望在官方文档的 python 版本更改日志中快速提及这一点,但希望这个答案对其他人也有用。
  • @pevogam:请注意,通过调用构造函数来反序列化对象存在微妙的危险,特别是对于共享对象或循环引用的情况。例如,this case 调用 ThingHolder.__init__ 3 次,一次手动调用,并且在 unpickling 中 两次,即使它正在 unpickling 的对象图只有一个 ThingHolder 实例。 This other case 完全失败并出现 RecursionError,尽管 succeeds 没有 __reduce__
  • (实际上,序列化和反序列化通常存在微妙的危险,但尝试通过调用构造函数来实现与尝试pickle的默认方式来实现不同的微妙危险。)
  • 我同意增加的不受欢迎的复杂性。不幸的是,实际的类不是由我创建的,并且包含许多不可拾取的对象,如锁和类似的东西。因此,有时有这样的替代方案很有用。
  • 这是我一直在寻找的解决方案!像@pevogam 一样,我有一个我没有创建的类(特别是从 C++ 生成的 Boost.Python 类),其中包含许多不可选择的对象。我试图使用__getstate____setstate____getinitargs__,但它们都没有工作。 __reduce__ 似乎成功了!
猜你喜欢
  • 1970-01-01
  • 2023-04-05
  • 2021-10-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多