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 -- https://mail.python.org/mailman/listinfo/python-list