pickle an instance of a custom class

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • PBlitz
    New Member
    • Mar 2008
    • 3

    pickle an instance of a custom class

    I want to save the content of a custom made OrderedDict. (I got the OrderedDict from http://aspn.activestat e.com/ASPN/Python)
    The pickle modul seemed to be the solution for the job.
    At first I tried to pickle the "nacked" OrderedDict derived from dict, but the pickle routine saves only a empty dict. A secont try to "replace" the __dict__ with the __getstate__ and __setstate__ methods also faild.

    How can I save the content (the items of the derived dict and the _keys list) of the OrderedDict via the pickle modul?

    here is the code:

    Code:
    class OrderedDict(dict):
        """This dictionary class extends UserDict to record the order in which items are 
        added. Calling keys(), values(), items(), etc. will return results in this order."""
           
        def __init__(self, d = None):
            self._keys = []
            if d == None: d = {}
            self.update(d)
            
        def __setitem__(self, key, item):
            dict.__setitem__(self,key, item)
            if key not in self._keys: self._keys.append(key)
    
        def items(self):
            return zip(self._keys, self.values())
    
        def keys(self):
            return self._keys[:]
    
        def update(self, d):
            dict.update(self, d)
            for key in d.keys():
                if key not in self._keys: self._keys.append(key)
        
        def __getstate__(self):
            """Return state values to be pickled."""
            return (dict(self.items()), self._keys)
    
        def __setstate__(self, state):
            """Restore state from the unpickled state values."""
            self.update(state[0])
            self._keys = state[1]
    
    if __name__ == "__main__":
        import pickle
        o = OrderedDict()
        o['a'] = [0,1]
        o['b'] = [2,3]
        p = pickle.dumps(o)
        u = pickle.loads(p)
        print o # output should be {'b': [2, 3], 'a': [0, 1]}
        print u # output should be {'b': [2, 3], 'a': [0, 1]}
    
    # Output:
    #{'b': [2, 3], 'a': [0, 1]}
    #{}
  • bvdet
    Recognized Expert Specialist
    • Oct 2006
    • 2851

    #2
    Originally posted by PBlitz
    I want to save the content of a custom made OrderedDict. (I got the OrderedDict from http://aspn.activestat e.com/ASPN/Python)
    The pickle modul seemed to be the solution for the job.
    At first I tried to pickle the "nacked" OrderedDict derived from dict, but the pickle routine saves only a empty dict. A secont try to "replace" the __dict__ with the __getstate__ and __setstate__ methods also faild.

    How can I save the content (the items of the derived dict and the _keys list) of the OrderedDict via the pickle modul?
    The dictionary elements will display in the correct order if you implement a __repr__() method. You will also need to override the dict.values() method so the values will be paired with the correct keys. Object pickling and unpickling should work without __getstate__() and __setstate__() methods.[code=Python]
    class OrderedDict(dic t):

    def __init__(self, d = None):
    self._keys = []
    if d == None: d = {}
    self.update(d)

    def __setitem__(sel f, key, item):
    dict.__setitem_ _(self,key, item)
    if key not in self._keys: self._keys.appe nd(key)

    def items(self):
    return zip(self._keys, self.values())

    def keys(self):
    return self._keys[:]

    def itervalues(self ):
    for k in self._keys:
    yield self[k]

    def values(self):
    return list(self.iterv alues())

    def update(self, d):
    dict.update(sel f, d)
    for key in d.keys():
    if key not in self._keys: self._keys.appe nd(key)

    def __repr__(self):
    return '{%s}' % ', '.join([': '.join([repr(k),str(v)]) \
    for k,v in zip(self.keys() , self.values())])

    if __name__ == "__main__":
    dd = OrderedDict()
    dd['z'] = [0,1]
    dd['b'] = [2,3]
    dd['x'] = [21,22]
    dd['y'] = [45,46]
    dd['a'] = [9,10]
    p = pickle.dumps(dd )
    u = pickle.loads(p)
    print dd
    print u[/code]
    Output:

    >>> {'z': [0, 1], 'b': [2, 3], 'x': [21, 22], 'y': [45, 46], 'a': [9, 10]}
    {'z': [0, 1], 'b': [2, 3], 'x': [21, 22], 'y': [45, 46], 'a': [9, 10]}
    >>>

    Comment

    • PBlitz
      New Member
      • Mar 2008
      • 3

      #3
      Thank you for the help. Unfortunately my output with your code is:
      {'z': [0, 1], 'b': [2, 3], 'x': [21, 22], 'y': [45, 46], 'a': [9, 10]}
      {}

      the pickle p contains:
      c__main__
      OrderedDict
      p0
      (tp1
      Rp2
      .

      This means the pickle dumps no dict values nor _keys list values.
      Maybe the reason is my configuration. I use jython 2.2.1 on a windows machine.
      Is there a implementation difference between python and jython?

      Comment

      • bvdet
        Recognized Expert Specialist
        • Oct 2006
        • 2851

        #4
        Originally posted by PBlitz
        Thank you for the help. Unfortunately my output with your code is:
        {'z': [0, 1], 'b': [2, 3], 'x': [21, 22], 'y': [45, 46], 'a': [9, 10]}
        {}

        the pickle p contains:
        c__main__
        OrderedDict
        p0
        (tp1
        Rp2
        .

        This means the pickle dumps no dict values nor _keys list values.
        Maybe the reason is my configuration. I use jython 2.2.1 on a windows machine.
        Is there a implementation difference between python and jython?
        I am using Python 2.3 on Windows XP. I don't know the differences. I have pickled class instances successfully many times. Your pickle module may be broken.

        Comment

        • PBlitz
          New Member
          • Mar 2008
          • 3

          #5
          Here a more precise description of the issue:
          Pickling of a class derived from dict creates an empty pickle in jython
          2.2.1. In contrast Python 2.5.2 delivers the expected result.
          So I assume a bug in the jython pickle module. Does anyone know if a developer release of jython already solves the problem? Or how to patch the module?

          # code describing the issue:

          Code:
          class MyDict(dict):
              def __init__(self, d = None):
                  if d == None: d = {}
                  dict.__init__(self, d)
          
          if __name__ == "__main__":
              import pickle
              md = MyDict({'b': [2, 3], 'z': [0, 1]})
              p = pickle.dumps(md)
              rd = pickle.loads(p)
              print "-> pickle p:\n", p
              print "-> MyDict md:\n", md
              print "-> reconstructed MyDict rd:\n", rd
          # jython 2.2.1 output with empty pickle p:

          -> pickle p:
          c__main__
          MyDict
          p0
          (tp1
          Rp2
          .
          -> MyDict md:
          {'b': [2, 3], 'z': [0, 1]}
          -> reconstructed MyDict rd:
          {}

          # in contrast python 2.5.2 output with filled pickle p:

          -> pickle p:
          ccopy_reg
          _reconstructor
          p0
          (c__main__
          MyDict
          p1
          c__builtin__
          dict
          p2
          (dp3
          S'b'
          p4
          (lp5
          I2
          aI3
          asS'z'
          p6
          (lp7
          I0
          aI1
          astp8
          Rp9
          .
          -> MyDict md:
          {'b': [2, 3], 'z': [0, 1]}
          -> reconstructed MyDict rd:
          {'b': [2, 3], 'z': [0, 1]}

          Comment

          Working...