views:

761

answers:

2

This might be a silly question but I couldn't find a good answer in the docs or anywhere.

If I use struct to define a binary structure, the struct has 2 symmetrical methods for serialization and deserialization (pack and unpack) but it seems ctypes doesn't have a straightforward way to do this. Here's my solution, which feels wrong:

from ctypes import *

class Example(Structure):
    _fields_ = [
        ("index", c_int),
        ("counter", c_int),
        ]

def Pack(ctype_instance):
    buf = string_at(byref(ctype_instance), sizeof(ctype_instance))
    return buf

def Unpack(ctype, buf):
    cstring = create_string_buffer(buf)
    ctype_instance = cast(pointer(cstring), POINTER(ctype)).contents
    return ctype_instance

if __name__ == "__main__":
    e = Example(12, 13)
    buf = Pack(e)
    e2 = Unpack(Example, buf)
    assert(e.index == e2.index)
    assert(e.counter == e2.counter)
    # note: for some reason e == e2 is False...
+4  A: 

The PythonInfo wiki has a solution for this.

FAQ: How do I copy bytes to Python from a ctypes.Structure?

def send(self):
    return buffer(self)[:]

FAQ: How do I copy bytes to a ctypes.Structure from Python?

def receiveSome(self, bytes):
    fit = min(len(bytes), ctypes.sizeof(self))
    ctypes.memmove(ctypes.addressof(self), bytes, fit)

Their send is the (more-or-less) equivalent of pack, and receiveSome is sort of a pack_into. If you have a "safe" situation where you're unpacking into a struct of the same type as the original, you can one-line it like memmove(addressof(y), buffer(x)[:], sizeof(y)) to copy x into y. Of course, you'll probably have a variable as the second argument, rather than a literal packing of x.

Mark Rushakoff
I tested this solution and it works as well. What was more important to me was that you found an official python.org entity (the FAQ in the wiki is good enough) state that hacking it is the way to go. I just felt as though these 2 functions/methods had to be somewhere in ctypes.py already so hacking it using pointers seemed very unpythonic. I know some people say ctypes isn't built for serializing etc, but I like the ctypes OOP-ness a lot more than the perl-ish struct module.
Mr Temp
+2  A: 

Gentlemen,

have a look at this link on binary i/o in python:

http://www.dabeaz.com/blog/2009/08/python-binary-io-handling.html

Based on this you can simply write the following to read from a buffer (not just files):

 g = open("foo","rb")
 q = Example()
 g.readinto(q)

To write is simply:

 g.write(q)

The same for using sockets:

 s.send(q)

and

 s.recv_info(q)

I did some testing with pack/unpack and ctypes and this approach is the fastest except for writing straight in C

Ralph Paul