[Numpy-discussion] Ctypes support in NumPy

Albert Strasheim fullung at gmail.com
Sun Jul 2 10:24:36 EDT 2006


Hello all

Travis Oliphant wrote:
> I've been playing a bit with ctypes and realized that with a little
> help, it could be made much easier to interface with NumPy arrays.
> Thus, I added a ctypes attribute to the NumPy array.  If ctypes is
> installed, this attribute returns a "conversion" object otherwise an
> AttributeError is raised.
> 
> The ctypes-conversion object has attributes which return c_types aware
> objects so that the information can be passed directly to c-code (as an
> integer, the number of dimensions can already be passed using c-types).
> 
> The information available and it's corresponding c_type is
> 
> data           -  c_void_p
> shape, strides -  c_int * nd  or c_long * nd or c_longlong * nd
> depending on platform

I did a few tests and this seems to work nicely:

In [133]: printf = ctypes.cdll.msvcrt.printf

In [134]: printf.argtypes = [ctypes.c_char_p, ctypes.c_void_p]

In [135]: x = N.array([1,2,3])

In [136]: printf('%p\n', x.ctypes.data)
01CC8AC0
Out[136]: 9

In [137]: hex(x.__array_interface__['data'][0])
Out[137]: '0x1cc8ac0'

It would be nice if we could the _as_parameter_ magic to work as well. See
this thread:

http://aspn.activestate.com/ASPN/Mail/Message/ctypes-users/3122558

If I understood Thomas correctly, in the presence of argtypes an an
instance, say x,  with _as_parameter_, the following is done to convert the
instance to something that the function accepts as its nth argument:

func.argtypes[n].from_param(x._as_parameter_)

However, if I try passing x directly to printf, I get this:

In [147]: printf('%p\n', x)
...
ArgumentError: argument 2: exceptions.TypeError: wrong type

However, this much works:

In [148]: ctypes.c_void_p.from_param(x._as_parameter_)
Out[148]: <cparam 'P' (01cc8ac0)>

So I don't understand why the conversion isn't happening automatically.

Another quirk I noticed is that non-void pointers' from_param can't seem to
be used with ints. For example:

In [167]: ctypes.POINTER(ctypes.c_double).from_param(x._as_parameter_)
...
TypeError: expected LP_c_double instance instead of int

But this works:

In [168]: ctypes.POINTER(ctypes.c_double).from_address(x._as_parameter_)
Out[168]: <ctypes.LP_c_double object at 0x01DCE800>

I don't think this is too much of an issue though -- you could wrap all your
functions to take c_void_ps. If you happen to pass an int32 NumPy array to a
function expecting a double*, you might run into problems though.

Maybe there should be a way to get a pointer to the NumPy array data as a
POINTER(c_double) if it is known that the array's dtype is float64. Ditto
for c_int/int32 and the others.

Regards,

Albert





More information about the NumPy-Discussion mailing list