使用 SWIG 控制器将 python 中的 numpy 函数传递给 C++

Posted

技术标签:

【中文标题】使用 SWIG 控制器将 python 中的 numpy 函数传递给 C++【英文标题】:Passing a numpy function in python to C++ using SWIG directors 【发布时间】:2015-03-25 23:44:32 【问题描述】:

我的代码主要是 C++,但我想使用 SWIG 导向器选项在 python 中重新定义一个 C++ 虚函数,然后将该函数传递回 C++。下面是一个简化的例子。

这是我的 C++ 基类,带有一个虚函数 funfun 接受(double* x, int n),它允许我将一个 numpy 数组传递给它。

class base
public:
    virtual double fun(double* x, int n)return 0.0;
;

我有另一个类接受这个基类:

class main
public:
    base* b_;

    main(base& b)
        b_ = &b; 
    
;

这个类有一个构造函数,它接受一个基类并存储一个指向它的指针(b_)。

我可以成功地将 swig 接口编译成一个名为 mymodule 的模块,确保启用导向器(请参阅下面的 SWIG 接口文件),并且根据 SWIG 导向器文档,我继承了基类并重新定义了虚函数 @ 987654328@如下:

import mymodule
class base(mymodule.base):
    def __init__(self):
        super(base,self).__init__()
    def fun(self,x):
        return x[0]

然后我将它传递给main 类:

b = base()
m = mymodule.main(b)

但是,当我尝试m.b_.fun(array([1.,2.])) 时,我得到了TypeError

TypeError: 'SwigPyObject' object has no attribute '__getitem__'

关于如何让它发挥作用的任何想法?我认为当我将b 传递给mymodule.main 时,C++ 将x 视为双* 指针并且不知道如何处理它。

顺便说一下,这是我的 swig 接口文件:

%module(directors="1") mymodule

%
#define SWIG_FILE_WITH_INIT
/* Includes the header in the wrapper code */
#include "myclasses.h"
%

%feature("director") base;

%init %
import_array();
%

%apply (double* IN_ARRAY1, int DIM1) (double* x, int n);

/* Parse the header file to generate wrappers */
%include "myclasses.h"

【问题讨论】:

b.fun(array([1.,2.]) 工作吗? 是的。但是当我将b 传递给m 时,它不会。 @kchow462 如果您想要任何不使用 swig 的工作解决方案,我已经使用 boost.python 从 C++ 到 python 再到 C++ 甚至 fork 再到 python 完成了类似的事情。查找文档非常乏味,但结果和生产力使我选择了这种方式。在我最近的工作中,django 从 C++ 启动了 zerorpc 接口并且工作正常。 谢谢梅尔。我可能不得不这样做,因为 SWIG 似乎没有办法做到这一点,或者至少,我不知道有什么办法。 【参考方案1】:

这看起来像是来自 Python 的所有权问题。

向 SWIG 提供提示:

%new double *fun(double* IN_ARRAY1, int DIM1) (double* x, int n);

还要注意指向函数本身的指针。 当使用 %new 时,Python 模块将分配对象的正确所有权。这就是为什么您可以在调用中使用值但不能使用变量的原因。

【讨论】:

我试过这个,但它似乎不起作用。我在我的 SWIG 接口文件中添加了 %new... 语句,但它仍然给我同样的错误。此外,它无法解决 C++ 函数接受 2 个参数而 Python 接受 1 个参数这一事实。【参考方案2】:

director 似乎无法识别您的 fun(double* x, int n) 的 Python 实现;它没有做那个函数的重载。

我怀疑原因是您的 Python 实现使用 numpy 作为参数。请注意,director 将调用抽象函数或实现的函数。

另一方面,%apply (double* IN_ARRAY1, int DIM1) (double* x, int n) 仅声明用于在 Python 中包装函数的类型映射逻辑,而不是向主管声明。请注意,这就是 b.fun(array([1.,2.]) 起作用的原因!也就是说,你应该向导演声明类型映射逻辑。

您可以在这里找到操作方法:

%typemap(directorin,numinputs=1) (double *x, int n)

    npy_intp dim = $2;
    $input = PyArray_SimpleNewFromData(1, &dim, NPY_DOUBLE, (void *)$1);

希望这能解决您的问题和其他未来的问题:)。我遇到了类似的问题,花了几天时间试图弄清楚。

【讨论】:

以上是关于使用 SWIG 控制器将 python 中的 numpy 函数传递给 C++的主要内容,如果未能解决你的问题,请参考以下文章

使用 SWIG 将 C++ 文件包装为 Python 文件

如何在 Python 中处理 SWIG 导向器方法中的 void 指针

如何使用 SWIG 将 C++ 数组转换为 Python 列表?

numpy.i 丢失。推荐的安装方式是啥?

使用 SWIG 绑定 Python/C++ 模板

Swig:将成员变量(指向值的指针)转换为 python 列表