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

How to pass python function as an argument to c++ function using Cython

本文关键字:函数 参数传递 c++ Cython python 何使用      更新时间:2023-10-16

以下是我的设置:我有下一个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)
   ...

有可能这样做吗?

你不能轻易做到:c++函数指针只是存储该函数代码开始的内存位置(或类似的东西,具体实现),而Python函数是一个完整的Python对象,带有存储字节码(可能是未编译的Python代码),文档字符串和其他一些位的字典。它也不是机器可以自己运行的形式-它需要Python解释器来处理字节码。没有一种方法可以将所有这些存储在c++函数指针中。

你可能能做的是使用c++ 11 std::function。这可以像函数指针一样使用,并且可以接受任何可调用对象(任何定义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);
    }
};

然后传递给setFooFunction一个c++类,该类存储PyObject* (Python函数的),并定义operator()来调用Python。

如果你不想自己编写c++类,boost::python::object类(http://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

并将其转换为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)));

由于o是可调用的,你应该能够直接在std::function

中使用它。
Foo foo; // a foo object
foo.setFooFunction(o); // pass it the boost::python::object

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