简体   繁体   中英

Python Class Inheritance : dict how to pickle(save, load)

I'm playing around with class inheritances and I'm stuck on how to pickle data in the class dictionary.

If dump only the dictionary part of self, when I load the dictionary back to self, self takes on a dict type instead of a class. But if I pickle the whole class then I get an error.

Error

pickle.PicklingError: Can't pickle <class 'main.model'>: it's not the same object as main.model 

Code

import os, pickle

class model(dict):
    def __init__( self ):
        pass

    def add( self, id, val ): 
        self[id] = val

    def delete( self, id ):   
        del self[id]

    def save( self ): 
        print type(self)
        pickle.dump( dict(self), open( "model.dict", "wb" ) )

    def load( self ): 
        print 'Before upacking model.dic, self ==',type(self)
        self = pickle.load( open( "model.dict", "rb" ) ) 
        print 'After upacking model.dic, self ==',type(self)

if __name__ == '__main__':
    model = model()
    #uncomment after first run
    #model.load()

    #comment after first run
    model.add( 'South Park', 'Comedy Central' )
    model.save()

If all you want to do is have a class called model that is a subclass of dict and can be properly pickled and unpickled back to an object that is also of type model then you don't have to do anything special. The methods you have defined in your example to add and delete are unnecessary you can just do them directly on model instances as you would do with any other dict. The save and load methods can be done using the pickle module instead of on the class itself.

code

import pickle

class model(dict):
    pass

a = model()
pickled = pickle.dumps(a)
b = pickle.loads(pickled)

print type(a), a
print type(b), b

output

<class '__main__.model'> {}
<class '__main__.model'> {}

below is another version which is maybe more in line with what you were trying to achieve. But you should NOT do things this way. The load method is weird so is the save. I put the code below to show it can be done but not really something you want to do because it will end up being very confusing.

another version (don't do this)

import pickle

class model(dict):
    def save(self):
        with open("model.dict", "wb") as f:
            pickle.dump(self, f)

    def load(self): 
        with open("model.dict") as f:
            return pickle.load(f)

#comment after first run
test = model()
test['South Park'] = 'Comedy Central'
test.save()
print type(test), test

#uncomment after first run
test2 = model().load()
print type(test2), test2

Further Reading

A great example of a subclass of dict that is is picklable is collections.OrderedDict . It is part of the python standard library and is implemented in python so you can have a peak at the source. The definition is 172 lines of code so it's not too much code to look through. It also had to implement the __reduce__ method to achieve pickling because it has information about the order of items that also needs to be pickled and unpickled. It's a good example of why you might want to make your own subclass of dict, it adds the very useful feature of respecting the order of values added to the dict.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM