如何使用Cython将python函数作为参数传递给c ++函数

时间:2015-05-25 12:02:23

标签: python c++ callback wrapper cython

以下是我的设置: 我有下一个要包装的c ++类:

// Foo.h
class Foo
{
public:
  typedef int MyType;
  typedef int ArgType1;
  typedef int ArgType2;
  ...
  typedef MyType (*FooFunction) (ArgType1 a, ArgType2 b);
  ...
  void setFooFunction(FooFunction f);

在c ++中使用此类的示例:

#include "Foo.h"
...
int fooFun(int a, int b)
{
  if (a > b) return a;
  else return b;
}
...
int main(int argc, char **argv)
{
  ...
  fooObj->setFooFunction(&fooFun);
  ...
}  

Cython包装器:

 # .pyx
 cdef extern from "Foo.h":
   cdef cppclass Foo:
     void setFooFunction(int *) except +

 def bar(fooFun):
   ...
   fooobj.setFooFunction(fooFun)
   ...

我希望能够做到这一点:

 # python file
 ...
 def pyfun(x, y):
   return x + y
 ...
 def main():
   bar(pyfun)

我完全不熟悉Cython,但是我已经尝试过做一些魔术并且它不起作用:

 # .pyx
 cdef extern from "Foo.h":
   cdef cppclass Foo:
     void setFooFunction(int *) except +

 ctypedef int (*myFun) (int, int)

 def bar(fooFun):
   cdef myFun funpointer
   funpointer = (<myFun*><size_t>id(smoothfun))[0]
   ...
   fooobj.setFooFunction(<int*>fooFun)
   ...

甚至可以做这样的事情吗?

1 个答案:

答案 0 :(得分:1)

你不能轻易地:一个C ++函数指针只是将位置存储在内存中,该函数的代码开始(或类似的,特定于实现),而Python函数是一个完整的Python对象,带有存储字节码的字典, (可能是未编译的Python代码),文档字符串和其他一些内容。它也不是机器可以独立运行的形式 - 它需要Python解释器来处理字节码。实际上没有办法将所有内容存储在C ++函数指针中。

您可以使用C ++ 11 std::function。这可以像函数指针一样使用,并且可以使用任何可调用对象(定义{{​​1}}的任何内容)。这个想法是你的类存储operator()而不是函数指针。

std::function

然后传递#include <functional> // for std::function class Foo { private: std::function<int(int,int)> stored_function; public: void setFooFunction(std::function<int(int,int)> f) { stored_function = f; } void doSomething() { // call it like this int result = stored_function(1,2); } }; 一个存储PyObject *(Python函数)的C ++类,并定义setFooFunction来调用Python。

如果您不想自己编写C ++类,operator()类(http://www.boost.org/doc/libs/1_58_0/libs/python/doc/v2/object.html#object_operators-spec)具有您需要的功能。您可以轻松地从Cython

获取PyObject *
boost::python::object

并将其转换为boost c ++类也很合理(http://www.boost.org/doc/libs/1_58_0/libs/python/doc/tutorial/doc/html/python/object.html#python.creating_python_object

from cpython.ref cimport PyObject
cdef PyObject* pyob_ptr = <PyObject*>some_function

由于boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj_ptr))); 可以调用,您应该可以直接在o

中使用它
std::function

(显然这里缺少很多细节,但希望广泛的方法有用!)