return a ctypes object to C
Arnaud Loonstra
arnaud at sphaero.org
Thu Oct 31 10:39:53 EDT 2019
On 31-10-2019 14:44, Thomas Jollans wrote:
> On 31/10/2019 14.13, Arnaud Loonstra wrote:
>> On 30-10-2019 09:32, Arnaud Loonstra wrote:
>>> Hi all,
>>>
>>> I'm trying to wrap my head around the ctypes API. I have a C
>>> structure I wish to create in Python and then return from python to C.
>>>
>>> So a python method is called from C and needs to return an object
>>> which we then process in C again.
>>>
>>> I have a binding to access and create the C methods and structures so
>>> in Python I can call the Zmsg() constructor. I now need to return this.
>>>
>>> My python test method is simply:
>>>
>>> def actor_test( *args, **kwargs):
>>> print("test")
>>> msg = Zmsg()
>>> frame = Zframe(b"Hello", 5)
>>> msg.prepend(frame)
>>> return msg
>>>
>>> the method is called from C as follows:
>>>
>>> PyObject *pReturn = PyObject_CallObject(pFunc, NULL);
>>>
>>> This correctly calls the method. However the returned object is of
>>> course a PyObject*. The debugger says it's
>>>
>>> "<czmq._czmq_ctypes.Zmsg object at 0x7ffff5f18e50>" PyObject
>>> [class] "<class 'czmq._czmq_ctypes.Zmsg'>"
>>> [super class] "<class 'object'>"
>>> [meta type] "<class 'type'>"
>>> ob_refcnt 1 Py_ssize_t
>>>
>>> However how I can I get it back to the original C type (zmsg_t *)
>>>
>>> Any help really appreciated.
>>>
>>
>> What I've found so far is that I can return the address of the ctypes
>> object.
>>
>> msg = Zmsg()
>> frame = Zframe(b"Hello", 5)
>> msg.prepend(frame)
>> return addressof(msg._as_parameter_.contents)
>>
>> In C I can then cast it back to the original type.
>>
>> PyObject *pReturn = PyObject_CallObject(pFunc, NULL);
>> assert(pReturn);
>> long bla = PyLong_AsLong(pReturn);
>> zmsg_t* test = (zmsg_t *)bla;
>> assert(test);
>> char *hello = zmsg_popstr(test);
>> assert(hello);
>> assert(streq(hello, "Hello"));
>>
>> This works, I'm not sure if this is the right way. It also creates a
>> complicated setup with the garbage collector.
>>
>> Anybody better ideas?
>
> You've already got a complicated setup with your ctypes objects...
>
> If you're using the Python C API anyway, why would you use ctypes at
> all? You can create custom Python types in C to wrap your C pointers.
>
> Alternatively: if you're using ctypes anyway, why use the Python C API
> at all? You can create C function pointers from Python functions with
> ctypes.
>
> If you're mixing two different ways of interfacing Python and C, the
> result will ALWAYS be messy. Better to stick to one. Personally, I
> prefer cffi or cython depending on the situation, as I find them clearer
> and easier to use than ctypes. Using the Python C API directly is
> usually the hardest to understand and the easiest to get wrong.
>
> -- Thomas
Hi Thomas,
I have an engine running which can call handlers. These handlers return
a zmsg_t (a message) which the engine then can process.
In this engine we have Python embedded and I want to use a Python method
as a handler. To embed Python we need to use the Python C API. To
construct a zmsg_t type in Python we need to call the corresponding C
method and we use ctypes to do that.
I'm using a ctypes binding because it already exists, it's here:
https://github.com/zeromq/czmq/blob/d6283985ba52fd8c3f8fbdc7cd5c08372ff69ca1/bindings/python/czmq/_czmq_ctypes.py#L4392
I know I can use cffi for example but that's IMHO just a ctypes
alternative.
Are you saying it's better to create some approach to create a zmsg_t
using the Python C API?
Please enlighten me if this should be done differently.
Rg,
Arnaud
More information about the Python-list
mailing list