Probably something like this:
def getdict(struct):
return dict((field, getattr(struct, field)) for field, _ in struct._fields_)
>>> x = S1()
>>> getdict(x)
{'A': <__main__.c_ushort_Array_10 object at 0x100490680>, 'C': 0L, 'B': 0L}
As you can see, it works with numbers but it doesn't work as nicely with arrays -- you will have to take care of converting arrays to lists yourself. A more sophisticated version that tries to convert arrays is as follows:
def getdict(struct):
result = {}
for field, _ in struct._fields_:
value = getattr(struct, field)
# if the type is not a primitive and it evaluates to False ...
if (type(value) not in [int, long, float, bool]) and not bool(value):
# it's a null pointer
value = None
elif hasattr(value, "_length_") and hasattr(value, "_type_"):
# Probably an array
value = list(value)
elif hasattr(value, "_fields_"):
# Probably another struct
value = getdict(value)
result[field] = value
return result
If you have numpy and want to be able to handle multidimensional C arrays, you should add import numpy as np and change:
value = list(value)
to:
value = np.ctypeslib.as_array(value).tolist()
This will give you a nested list.
Answer from Tamás on Stack OverflowProbably something like this:
def getdict(struct):
return dict((field, getattr(struct, field)) for field, _ in struct._fields_)
>>> x = S1()
>>> getdict(x)
{'A': <__main__.c_ushort_Array_10 object at 0x100490680>, 'C': 0L, 'B': 0L}
As you can see, it works with numbers but it doesn't work as nicely with arrays -- you will have to take care of converting arrays to lists yourself. A more sophisticated version that tries to convert arrays is as follows:
def getdict(struct):
result = {}
for field, _ in struct._fields_:
value = getattr(struct, field)
# if the type is not a primitive and it evaluates to False ...
if (type(value) not in [int, long, float, bool]) and not bool(value):
# it's a null pointer
value = None
elif hasattr(value, "_length_") and hasattr(value, "_type_"):
# Probably an array
value = list(value)
elif hasattr(value, "_fields_"):
# Probably another struct
value = getdict(value)
result[field] = value
return result
If you have numpy and want to be able to handle multidimensional C arrays, you should add import numpy as np and change:
value = list(value)
to:
value = np.ctypeslib.as_array(value).tolist()
This will give you a nested list.
A little bit more general purpose to handle double arrays, and arrays of structures, and bitfields.
def getdict(struct):
result = {}
#print struct
def get_value(value):
if (type(value) not in [int, float, bool]) and not bool(value):
# it's a null pointer
value = None
elif hasattr(value, "_length_") and hasattr(value, "_type_"):
# Probably an array
#print value
value = get_array(value)
elif hasattr(value, "_fields_"):
# Probably another struct
value = getdict(value)
return value
def get_array(array):
ar = []
for value in array:
value = get_value(value)
ar.append(value)
return ar
for f in struct._fields_:
field = f[0]
value = getattr(struct, field)
# if the type is not a primitive and it evaluates to False ...
value = get_value(value)
result[field] = value
return result
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.
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_into(q)
I did some testing with pack/unpack and ctypes and this approach is the fastest except for writing straight in C
Just create a pointer, assign the data afterwards;
import ctypes
class EmxArray(ctypes.Structure):
""" creates a struct to match emxArray_real_T """
_fields_ = [('data', ctypes.POINTER(ctypes.c_double)),
('size', ctypes.POINTER(ctypes.c_int)),
('allocatedSize', ctypes.c_int),
('numDimensions', ctypes.c_int),
('canFreeData', ctypes.c_bool)]
data = (1.3, 3.5, 2.7, 4.1)
L = len(data)
e = EmxArray()
e.data = (ctypes.c_double * L)(*data)
e.size = (ctypes.c_int * 1)(L)
# et cetera
I'm not well-versed with the Python-C interface, so what I'm suggesting may be less than ideal. My guess is that likely the crash is because x->data is never initialized and the memory to which it is pointing isn't allocated.
An approach I have taken when interfacing to MATLAB Coder generated code from other languages in the presence of emxArray arguments is to hand-write a C interface function that provides a simpler API. This relieves the burden of needing to construct an emxArray in the other environment (Android Java in my particular case). If the generated function foo takes and returns a 2-D double array, then something like the following could work:
void foo(double *x, int *szx, double **y, int *szy);
This function would take a pointer to the input data and its size and provide a pointer to the output data and its size. The implementation would look something like:
void foo(double *x, int *szx, double **y, int *szy)
{
emxArray_real_T *pEmx;
emxArray_real_T *pEmy;
/* Create input emxArray assuming 2-dimensional input */
pEmx = emxCreateWrapper_real_T(x, szx[0], szx[1]);
/* Create output emxArray (assumes that the output is not */
/* written before allocation occurs) assuming 2-D output */
pEmy = emxCreateWrapper_real_T(NULL, 0, 0);
/* Call generated code (call foobar_initialize/terminate elsewhere) */
foobar(pEmx, pEmy);
/* Unpack result - You may want to MALLOC storage in *y and */
/* MEMCPY there alternatively */
*y = pEmy->data;
szy[0] = pEmy->size[0];
szy[1] = pEmy->size[1];
/* Clean up any memory allocated in the emxArrays (e.g. the size vectors) */
emxDestroyArray_real_T(pEmx);
emxDestroyArray_real_T(pEmy);
}
You should be able to call this function from Python more simply and pass in the desired data as needed.
My other answer has more details on the emxArray_* functions found in the file foobar_emxAPI.h.