typing python functions to use them as callback

118 views
Skip to first unread message

Johannes Kulick

unread,
Apr 17, 2015, 4:46:59 AM4/17/15
to cython...@googlegroups.com
Hi all,

I'm quite new to cython, so apologies for stupid questions...

Here is my problem:

We have a C++ library (which optimizes robot trajectories if that matters), which gets std::function objects as callback. Let's say, they look like this:

class Optimizer {
   
public:
       
void optimize(std::function<double(double)> cost_fnc);
};

Giving it a cython function is easy (as function_pointers get casted to std::function and I can specify the desired signature in cython etc.).

cdef double my_cost_fnc(double x):
   
return x*3

# ...

o
= Optimizer()
o
.optimize(my_cost_fnc)

But now, we would like to give people the possibility to implement pure python functions without rebuilding the cython module and that's where my problem starts. Python functions do of course have not the right signature. The first thought was to make a local cdef and use that:

cdef void optimize_wrapper(func):
    cdef
double func_wrapper(double d):
       
return func(d)
    o
.optimize(func_wrapper)

But local cdef is not allowed. Ok, I thought, than I move it out and use functools.partial

cdef double func_wrapper(double d, func):
   
return func(d)

cdef
void optimizer_wrapper(func):
    wrapped
= functools.partial(func_wrapper, func=func)
    o
.optimize(wrapped)

But then functools.partial returns of course a python object.

In the end I did the closure in C++, and wrapped everything with a void pointer and function pointers:

void optimize_wrapper(void* python_function, double (*cost) (void*, double)) {
  optimize
([](double x) { return cost(python_function, x); });  
}

But then I have to touch the original library (or add another cpp file). Although it works, it feels a bit wrong. Is there any other way to achieve, what I want?

Cheers,
Johannes

Nils Bruin

unread,
Apr 17, 2015, 9:10:54 PM4/17/15
to cython...@googlegroups.com
On Friday, April 17, 2015 at 1:46:59 AM UTC-7, Johannes Kulick wrote:
But then functools.partial returns of course a python object.

Can't you use the C++ variant of it, i.e., std::bind? From what I understand you should be able to use the result from std::bind in a situation where std::function is expected.
So if you write a cython wrapper that takes a python object and the parameters taken by your callback, which calls the python object with the parameters, then you should be able to use std::bind to bind the python object parameter and obtain a std::function object of the desired signature.

Johannes Kulick

unread,
Apr 20, 2015, 7:39:21 AM4/20/15
to cython...@googlegroups.com
That's what I do (but with lambdas instead of std::bind). I just thought closures are so fundamental in python that it would be nice to do it on the python side. 
Reply all
Reply to author
Forward
0 new messages