views:

150

answers:

3

Hey All,

I am working on a project built on python 2.4 (It is an embedded python project, so I don't have a choice on the version of python used). Throughout the application, we use array.array to store data.

Support for pickling array.array objects was added to pickle (and cPickle) in 2.5. We have a viable workaround in 2.4 when using the pure python pickle class (we subclass Pickler/Unpickler to handle arrays) but this does not work with cPickle (we need this due to performance problems).

Any suggestions?

EDIT -- SOLUTION:

This is the final code that seems to be working (thanks for the suggestions):

# Add serialization for array objects
def array_unpickler(data):
    return array.array(data[0], data[1:])
def array_pickler(arr):
    return array_unpickler, ("%s%s" % (arr.typecode, arr.tostring()),)
copy_reg.pickle(array.ArrayType, array_pickler, array_unpickler)
+1  A: 

I'm not sure if the array type can be augmented with a __reduce__ method (perhaps with a subclass), but you could always try converting your arrays to sequences & back again... if the built-in extension mechanism won't work for you. (hack)

I haven't tried this before, but you could try adding support via copy_reg... essentially the same result as implementing __reduce__ on your own class or subclass, but a tad cleaner.

Pestilence
For arrays I would convert them to a large string object with `.tostring()`, which is just a copy of the in-memory bytes representing the array.
Joe Koberg
With this approach you would also want to include the array's typecode.I've tried this approach but am running into problems getting the typecode state into the unpickled object. I've been trying to figure out `__initargs__` to little avail... I think I am going to take the `copy_req` approach.
Paul Osborne
+2  A: 

You can use the standard library module copy_reg to register functions to deal with pickling instances of types that don't natively support pickling; cPickle will use your registered functions where needed. I'd apply exactly this "hook" approach to your requirement of pickling instances of array.array.

Alex Martelli
Excellent! I've gotten it working. Your suggestion led me to http://effbot.org/librarybook/copy-reg.htm , which provides a couple excellent examples.
Paul Osborne
+1  A: 

Looks like you can pickle them, but you can't unpickle the result

Python 2.4.5 (#2, Jan 21 2010, 20:05:55) 
[GCC 4.2.4 (Ubuntu 4.2.4-1ubuntu3)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import cPickle as pickle
>>> import array
>>> a=array.array('i','12345678')
>>> pickle.dumps(a,2)
'\x80\x02carray\narray\nq\x01)\x81q\x02.'
>>> b=pickle.loads(_)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: array() takes at least 1 argument (0 given)

Looks the the dumps doesn't even include information about the typecode..or even the data :(

>>> a=array.array('c','abcdefghijkl') 
>>> pickle.dumps(a,2)                                                                                                                                                                             
'\x80\x02carray\narray\nq\x01)\x81q\x02.'
>>> 
gnibbler
Yep, this seems to confirm this bug from the python mailing list: http://mail.python.org/pipermail/python-bugs-list/2006-January/031597.htmlThe "smarts" were added in 2.5
Paul Osborne