1

I have a function with void * parameter and I want to store it in the dict.

What I do is:

%%cython

cdef void foo(void * bar):
    pass

cdef dict foobar = {'foo': foo}

But this code raises an Error: Cannot convert 'void (void *)' to Python object Any ways to overcome this problem?

Ivan Mishalkin
  • 1,049
  • 9
  • 25

2 Answers2

3

The easiest solution is to create a cdef class that can wrap this function. Since the cdef class is a Python object it can be stored in a dictionary like any other Python object.

ctypedef void (*void_func_ptr)(void*)

cdef class VoidFuncWrapper:
    cdef void_func_ptr func
    def __cinit__(self):
       self.func = NULL

    @staticmethod
    cdef VoidFuncWrapper make_from_ptr(void_func_ptr f):
        cdef VoidFuncWrapper out = VoidFuncWrapper()
        out.func = f
        return out

Then you can simply do:

cdef dict foobar = {'foo': VoidFuncWrapper.make_from_ptr(foo)}
DavidW
  • 29,336
  • 6
  • 55
  • 86
0

Your problem here is that void* has no defined converter from a Python object, so a Python wrapper function (that accepts Python objects, converts them, and passes them to the underlying C function) can't be defined, either explicitly with cpdef or implicitly by putting the cdef function in a Python object (the dict in this case).

You could make this work by defining the argument to be something Cython knows how to convert to, e.g.:

cpdef void foo(const char * bar):
    pass

cdef dict foobar = {'foo': foo}

Try it online!

But that may not work for your scenario if the function needs to accept an arbitrary pointer. If that's the case, you may want to switch to using C++ containers that can hold your function pointer type directly:

from libcpp.unordered_map cimport unordered_map
from libcpp.string cimport string

cdef void foo(void *bar):
    pass

ctypedef void (*f_type)(void *)

cdef unordered_map[string, f_type] foobar

foobar['foo'.encode('ascii')] = foo
ShadowRanger
  • 143,180
  • 12
  • 188
  • 271
  • I have rapleced `cdef` with `cpdef` but still cann't add the function to the dict. By the way, if I remove all the arguments from the fuction, the code above works fine – Ivan Mishalkin Aug 12 '19 at 13:20
  • 2
    @shadowrander `cpdef` doesn't make any sense because a Python function can accept a `void*` argument – DavidW Aug 12 '19 at 13:25
  • @IvanMishalkin: I updated my answer. DavidW's answer is probably better for a general purpose solution, but mine is an alternative for specific use cases. – ShadowRanger Aug 12 '19 at 13:42