Monday, January 12, 2009

SWIG and Pickle

I have yet to see any site that explains how to pickle swig objects well enough. SWIG objects exist both on the Python and C++ side.

Without calling the __init__ function on the Python class instance of a SWIG object, it doesn't exist as far as SWIG is concerned. So you'll get a TypeError on the 'self' parameter of your functions.

If we were using old-style classes, __getinitargs__ would work well enough. Since we aren't, as far as I can tell, it's necessary for us to call the initializer ourselves.
def generic_setstate(self, dict):
self.__init__()
for key, value in dict.iteritems():
setattr(self, key, value)

def generic_getstate(self):
return dict((var, getattr(self, var)) for var in
__pickle_vars__[self.__class__.__name__])
If you have the dict __pickle_vars__ set up such as:
__pickle_vars__ = { 'myclass' : ['x', 'y'], 'myclass2' : ['zz'], ... }
You can then set:
myclass.__getstate__=generic_getstate
myclass.__setstate__=generic_setstate


EDIT 2009/1/14:
If you use properties for all those C++ getters/setters (as you should be doing), you can then iterate over all of the properties for a much cleaner solution. It takes even more tweaking to get pickling to work with outputs from factory products (e.g., trying to pickle a b2Body instead of a b2BodyDef). Expect something like this to show up soon in pybox2d. :)

1 comment:

  1. A very useful post! In fact, AFAIK this is the only method to use pickle with SWIG objects. Defining __reduce__ method or using copy_reg does not work.

    ReplyDelete