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

dim*_*.sp 6 c++ python 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);
Run Code Online (Sandbox Code Playgroud)

在 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);
  ...
}  
Run Code Online (Sandbox Code Playgroud)

Cython 包装器:

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

 def bar(fooFun):
   ...
   fooobj.setFooFunction(fooFun)
   ...
Run Code Online (Sandbox Code Playgroud)

我希望能够做到这一点:

 # python file
 ...
 def pyfun(x, y):
   return x + y
 ...
 def main():
   bar(pyfun)
Run Code Online (Sandbox Code Playgroud)

我不完全熟悉 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)
   ...
Run Code Online (Sandbox Code Playgroud)

甚至有可能做这样的事情吗?

Dav*_*idW 3

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

您可以做的是使用 C++11 std::function。这可以像函数指针一样使用,并且可以采用任何可调用对象(任何定义的东西operator())。这个想法是你的类存储 astd::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);
    }
};
Run Code Online (Sandbox Code Playgroud)

然后,您传递setFooFunction一个存储 PyObject*(Python 函数)的 C++ 类,并定义operator()对 Python 的调用。

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

from cpython.ref cimport PyObject
cdef PyObject* pyob_ptr = <PyObject*>some_function
Run Code Online (Sandbox Code Playgroud)

将其转换为 boost c++ 类也相当简单(http://www.boost.org/doc/libs/1_58_0/libs/python/doc/tutorial/doc/html/python/object.html#python.creating_python_object

boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj_ptr)));
Run Code Online (Sandbox Code Playgroud)

既然o是可调用的,你应该可以直接在std::function

Foo foo; // a foo object
foo.setFooFunction(o); // pass it the boost::python::object
Run Code Online (Sandbox Code Playgroud)

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