为什么pickle.dumps调用__getattr__?

时间:2012-08-23 23:55:05

标签: python serialization pickle

import cPickle

class Foo(object):
    def __init__(self):
        self._data = {'bar': 'baz'}

    def __getattr__(self, name):
        assert hasattr(self, '_data')
        return self._data[name]

    # I even had to define this just to stop KeyError: '__getstate__'
    def __getstate__(self):
        return self.__dict__

foo = Foo()
bar = cPickle.dumps(foo)
cPickle.loads(bar)

这会引发断言错误。

我认为pickle / cPickle只是在转储时将__dict__转换为字符串,然后在加载时直接使用该字符串设置新对象的__dict__。为什么dumps需要致电bar.__getattr__?如何更改Foo以避免这种情况?

1 个答案:

答案 0 :(得分:2)

根据cPickle的文档:http://docs.python.org/library/pickle.html

object.__getstate__()
  

类可以进一步影响他们的实例被腌制的方式;如果类定义方法__getstate__(),则调用它并将返回状态作为实例的内容进行pickle,而不是实例的字典的内容。如果没有__getstate__()方法,则会对实例的__dict__进行pickle。

     

请注意

     

在上映时间,某些方法如__getattr__(),   可以在实例上调用__getattribute__()__setattr__()。如果这些方法依赖于某些内部不变量为真,那么   类型应该实现__getinitargs__()__getnewargs__()来实现   建立这样的不变量;否则,__new__()也不是   __init__()将被调用。

由于您试图声明hasattr(self, '_data')为True,我相信您需要使用__getinitargs__()__getnewargs__()。这是因为在使用pickle时,不会调用类__init__方法。