How to pickle an object of a class B (having many variables) that inherits from A, that defines __setstate__ and __getstate__

给你一囗甜甜゛ 提交于 2019-12-12 11:37:35

问题


My problem is:

class A(object):
    def __init__(self):
        #init
    def __setstate__(self,state):
        #A __setstate__ code here            
    def __getstate__(self):
        #A __getstate__ code here
        return state

class B(A):
    def __init__(self):
        #creates many object variables here

A is from an external library.

Hard solution

This I would like to avoid

When pickling B, pickle of course uses class A's __setstate__, __getstate__ methods, so in order for pickle to work I should do something like this:

class B(A):
    def __init__(self):
        #creates many object variables here

    def __setstate__(self,state)
        A.__setstate__(self,state)
        #B __setstate__ code here
        #getting various variables from state for example
        self._a0 = state['a0']
        self._a1 = state['a1']
        #...
        self._a100 = state['a100']
        self._a101 = state['a101']

    def __getstate__(self):
        state = A.__getstate__(self)
        #B __setstate__ code here
        #filling state with various variables  
        #getting various variables from state for example
        state['a0'] =  self._a0
        state['a1'] =  self._a1
        #...
        state['a100'] =  self._a100
        state['a101'] =  self._a101           
        return state

My question is:

How can I avoid defining __setstate__ and __getstate__ in B so that pickle does the job of pickling variables by itself? All variables in B are of type that pickle may pickle(handle) by itself. So if B didn't inherit from A, it would be possible with good results:

b = B()
path = 'path.temp'
fout = open(path,'w')
pickler = pickl.Pickler(fout)

pickler.dump(b)
fout.close()

fin = open(path,'r')
upickler = pickl.Unpickler(fin)
b = unpickler.load()
fin.close()
#b has all variables

The obvious solution

class B(object):
    def __init__(self):
        #creates many object variables here
        a = A()            

However I would like B to inherit from A. Any idea how to solve this or at least automate pickling/unpickling variables in B?

The workaround solution:

As for automating pickling in the Hard Solution

Add to B a dictionary holding variables to pickle:

class B(A):
    __picklableObjects__ = {'_a0', '_a1', ... ,'_a101'}

    def __init__(self):
        #creates many object variables here
        A.__init__(self)
        self._a0 = ...
        ...
        self._a101 = ...

    @staticmethod
    def getPicklableObjects():
        return B.__picklableObjects__

    def __setstate__(self,state):
        A.__setstate__(self,state)
        for po in B.getPicklableObjects():
           __dict__[po] = state[po]

    def __getstate__(self):
        state = A.__getstate__(self)
        for po in B.getPicklableObjects():
            state[po] = copy.deepcopy(__dict__[po])
        return state

Any other ideas?

A's library:

Ok so for any of you interested A is graph_tool.Graph: A src code

line 786: class Graph(object)

...

line 1517: __getstate__

...

line 1533: __setstate__

回答1:


According to the documentation, when __getstate__ isn't defined, the instance's __dict__ is pickled so maybe, you can use this to define your own state methods as a combination of the A methods and the instance's __dict__:

import pickle

class A(object):
    def __init__(self):
        self.a = 'A state'

    def __getstate__(self):
        return {'a': self.a}

    def __setstate__(self, state):
        self.a = state['a']

class B(A):
    def __init__(self):
        A.__init__(self)
        self.b = 'B state'

    def __getstate__(self):
        a_state = A.__getstate__(self)
        b_state = self.__dict__
        return (a_state, b_state)

    def __setstate__(self, state):
        a_state, b_state = state
        self.__dict__ = b_state
        A.__setstate__(self, a_state)

b = pickle.loads(pickle.dumps(B()))
print b.a
print b.b



回答2:


The default behavior of Pickle is __getstate__ is not defined is to pickle the contents of the objects __dict__ attribute - that is where the instance attributes are stored.

Therefore it looks like in your case, all you need to do is to make A's get and set state to preserve the values found in self.__dict__ and restore then at __setstate__ - this should preserve the instance variables of all instances of subclasses of A as well.



来源:https://stackoverflow.com/questions/8574742/how-to-pickle-an-object-of-a-class-b-having-many-variables-that-inherits-from

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!