is it possible to pass a python function as c function pointer?

1,177 views
Skip to first unread message

Jiajun Huang

unread,
Jan 16, 2017, 2:31:48 AM1/16/17
to cython-users
I'm trying to binding a c library to python. The library uses lots of generic function pointers:

int arraylist_index_of(ArrayList *arraylist,
                       ArrayListEqualFunc callback,
                       ArrayListValue data)
{
unsigned int i;

for (i=0; i<arraylist->length; ++i) {
if (callback(arraylist->data[i], data) != 0)
return (int) i;
}

return -1;
}

and the prototype of ArrayListEqualFunc is: 

typedef int (*ArrayListEqualFunc)(ArrayListValue value1, ArrayListValue value2);

when I do this:

# carraylist.pxd
cdef extern from "calg/src/arraylist.h":
    # ...

    ctypedef bint (*ArrayListEqualFunc)(
        ArrayListValue value1, ArrayListValue value2
    )

# arraylist.pyx
cdef class ArrayList:

    cdef int _indexof(self, EQUALFUNC cmp_func, object item):
        return <int>carraylist.arraylist_index_of(
                self.__c_array_list, cmp_func, <void *>item
            )

    def indexof(self, item):
        return self._indexof(<EQUALFUNC>operator.eq, item)

compile it, and I got:

Compiling calgdqueue.pyx because it changed.
Compiling arraylist.pyx because it changed.
[1/2] Cythonizing arraylist.pyx

Error compiling Cython file:
------------------------------------------------------------
...
        return <int>carraylist.arraylist_index_of(
                self.__c_array_list, cmp_func, <void *>item
            )

    def indexof(self, item):
        return self._indexof(<EQUALFUNC>operator.eq, item)
                            ^
------------------------------------------------------------

arraylist.pyx:58:29: Python objects cannot be cast to pointers of primitive types
Traceback (most recent call last):
  File "setup.py", line 15, in <module>
    ext_modules=cythonize(ext_modules)
  File "/usr/lib/python3.6/site-packages/Cython/Build/Dependencies.py", line 934, in cythonize
    cythonize_one(*args)
  File "/usr/lib/python3.6/site-packages/Cython/Build/Dependencies.py", line 1056, in cythonize_one
    raise CompileError(None, pyx_file)
Cython.Compiler.Errors.CompileError: arraylist.pyx

is it possible to pass a python function(e.g. operator.eq) as c function pointers by cython?

Jiajun Huang

unread,
Jan 16, 2017, 9:13:54 AM1/16/17
to cython-users
I've done it by wrap the function in a cdef function: https://github.com/jiajunhuang/pyalgorithms/blob/master/arraylist.pyx but I wonder is there any better solution?

在 2017年1月16日星期一 UTC+8下午3:31:48,Jiajun Huang写道:

Robert Bradshaw

unread,
Jan 16, 2017, 4:14:51 PM1/16/17
to cython...@googlegroups.com
A well written library will accept an arbitrary void* argument along
with the callback function pointer which is then returned when the
callback is called (as C doesn't have language support for closures).
You can then use this to stash away your Python callable. See the
example at

https://github.com/cython/cython/blob/master/Demos/callback/cheese.pyx

If the function you're wrapping is fixed, as in your case, just
defining a cdef function is probably sufficient.
> --
>
> ---
> You received this message because you are subscribed to the Google Groups
> "cython-users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to cython-users...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages