python – 为什么pickle.dumps调用__getattr__?

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__.为什么转储需要调用bar .__ getattr__?我怎样才能改变Foo以避免这种情况?

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

object.__getstate__()

Classes can further influence how their instances are pickled; if the class defines the method __getstate__(), it is called and the return state is pickled as the contents for the instance, instead of the contents of the instance’s dictionary. If there is no __getstate__() method, the instance’s __dict__ is pickled.

Note

At unpickling time, some methods like __getattr__(),
__getattribute__(), or __setattr__() may be called upon the instance. In case those methods rely on some internal invariant being true, the
type should implement either __getinitargs__() or __getnewargs__() to
establish such an invariant; otherwise, neither __new__() nor
__init__() will be called.

既然你试图断言hasattr(self,’_ data’)是True,我相信你需要使用__getinitargs __()或__getnewargs __().这是因为在使用pickle时,不会调用类__init__方法.

点赞