Eurydice
Eurydice

Reputation: 8429

error when unpickling a class from its constructor

I would like to implement a class (ideally a singleton) for which the state should be restored using cPickle mechanism at initialization stage. To do so I wrote the following snippet:

import cPickle
import collections

class Test(collections.OrderedDict):

    path = "test.cp"

    def __init__(self):

        self.path = "test.cp"

        collections.OrderedDict.__init__(self)
        try:
            f = open(Test.path,"rb")
        except IOError:
            return
        else:
            ud = cPickle.load(f)
            self.update(ud)
            f.close()

    def save(self):

        f = open(Test.path,"wb")
        cPickle.dump(self,f)
        f.close()

if __name__ == "__main__":
    t = Test()
    t.save()
    t1 = Test()

Running that snippet produces the following error:

    Traceback (most recent call last):
  File "C:\Documents and Settings\pellegrini\Bureau\test.py", line 31, in <module>
    t1 = Test()
  File "C:\Documents and Settings\pellegrini\Bureau\test.py", line 18, in __init__
    ud = cPickle.load(f)
TypeError: ('__init__() takes exactly 1 argument (2 given)', <class '__main__.Test'>, ([],))

When inheriting from a dict instead of a collections.OrderedDict this works. From other similar posts, this may have something to do with __reduce__ method but I do not understand why and how ?

Would you have any idea about how to solve this problem ?

thanks a lot

Eric

Upvotes: 1

Views: 379

Answers (1)

User
User

Reputation: 14873

I guess that the OrderedDict has its own way of serialization.

def __init__(self, *args):

    self.path = "test.cp"

    collections.OrderedDict.__init__(self, *args)

try this and you get a recursion problem because pickle uses __init__.

An error free solution is:

import cPickle
import collections

class Test(collections.OrderedDict):

    path = "test.cp"

    def __init__(self, *args):

        self.path = "test.cp"

        collections.OrderedDict.__init__(self, *args)
        if not args:
            try:
                f = open(Test.path,"rb")
            except IOError:
                return
            else:
                ud = cPickle.load(f)
                self.update(ud)
                f.close()

    def save(self):

        with open(Test.path,"wb") as f:
            cPickle.dump(self,f)

if __name__ == "__main__":
    t = Test()
    t.save()
    t1 = Test()

Singleton

import pickle
import collections

_Test_singleton = None

class Test(collections.OrderedDict):

    path = "test.cp"

    def __new__(self, *args, **kw):
        global _Test_singleton
        if _Test_singleton is not None:
            return _Test_singleton
        _Test_singleton = collections.OrderedDict.__new__(self, *args, **kw)
        _Test_singleton.load()
        return _Test_singleton

    def __init__(self, *args):
        collections.OrderedDict.__init__(self, *args)

    def load(self):
        try:
            f = open(self.path,"rb")
        except IOError:
            return
        else:
            try:
                ud = pickle.load(f)
            finally:
                f.close()
            self.update(ud)

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


if __name__ == "__main__":
    t = Test()
    t.save()
    t1 = Test()
    assert t is t1

Upvotes: 3

Related Questions