为什么python`__setstate__`接受`None`作为参数?

时间:2014-02-18 00:06:35

标签: python serialization pickle

我正在浏览serge pygame engine中的一些代码,然后我在serge.serialize中找到了我无法绕过的东西:

def __setstate__(self, state=None):
        """Initialize the object to the given state for unpickling"""
        self.initial_properties = Bag()
        #
        # Initialize first from the defaults and then from the live state
        for this_state in (self.__class__._getProperties(), state):
            if this_state:
                for name, value in this_state:
                    setattr(self, name, value)
                    setattr(self.initial_properties, name, value)

此方法是从Serializable对象中检索的。我感到困惑的是,state中的__setstate__参数的默认值为None。为什么在取消对象时不会将状态发送到__setstate__,在什么情况下这会有用呢?

1 个答案:

答案 0 :(得分:4)

如果您的课程完全依赖__getstate__ / __setstate__进行腌制,则此功能无效。

正如__setstate__上的文档解释:

  

取消排版时,如果类定义了__setstate__(),则会以未选中的状态调用它...如果__getstate__()返回false值,则取消时不会调用__setstate__()方法。< / p>

因此,如果您的__getstate__返回None,则会在__setstate__时将其传回给您;你不会被召唤。

但请注意,在2.x version中,对于经典类而言并非如此。对于经典类,“如果一个类定义__getstate__()__setstate__(),则状态对象不必是字典,这些方法可以做他们想要的。” (事实上​​,我相信在某些情况下,任何虚假值都会转变为{},但这种情况并没有很好地记录,但同样的if语句会处理... {/ p>

但是,这并不能解释为什么你需要一个默认值......如果你能得到None,你肯定需要编写处理None的代码......但是你没有需要编写完全没有参数的代码,对吗?

但是,你有理由这样做。

首先,请注意,此特定类的__setstate__比平常更多:它首先从默认值开始,然后从实时状态初始化“。因此,单元测试非常有用,从默认值开始初始化是有效的。

除此之外,如果您定义自定义__reduce__方法和unreducer,则没有理由必须遵循与默认的unreducer完全相同的规则。或者当然没有理由它必须完全调用__setstate__ - 但是,如果您正在构建一个您期望用户进行子类化的基类,那么您的unreducer就可以工作了与默认设置一样,因此您的用户只需覆盖__setstate__,而不是添加自己的整个__reduce__实施。

同样,如果您在pickle / copyreg之上构建自己的序列化程序,而不是按原样使用它,那么您的代码就不必使用完全相同的规则pickle。同样,它没有理由使用甚至类似的规则,但这样做可能会让您的用户更容易扩展您的类。

这些是否适用于serge,我不知道,但它们都可以轻松应用于您可能想要构建的各种类型。