[英]Using SWIG for functions with functions as input parameter
考虑以下最小的例子:我有一个C ++函数'myfun',它接受一个数字和另一个函数作为输入,并返回在x处计算的函数:
双myfun(双x,双(* f)(双y))
{return f(x); }
我将此代码存储在'test.cpp'中。 相应头文件'test.hpp'中的代码很简单
double myfun(double x,double(* f)(double y));
现在,我尝试使用SWIG从Python访问'myfun'。 'swig.i'文件如下所示:
%模块测试
%{
#include“test.hpp”
%}
double myfun(double x,double(* f)(double y));
每当我尝试在Python中调用此函数时,例如使用
从测试导入myfun
myfun(2,lambda y:y ** 2)
我收到错误:
在方法'myfun'中,参数2'double(*)(double)'
所以我的问题很简单:如何修改'swig.i'文件,以便我可以将任何(合适的Python)函数传递给'myfun'? (这个问题与这篇文章有点相关如何包装一个c ++函数,它使用SWIG接收python中的函数指针 '但不同之处在于我在C ++中没有指定输入函数,而是我想保持它为一个免费的“参数”)。
在编写绑定时回调需要额外的处理,这在SWIG中尚未得到支持,显然没有真正的解决方法。
重点是SWIG是关于从Python(和其他语言)调用C,而不是从C调用Python。
我们使用的是SIP ,它是一个更复杂的绑定生成器(不过是C ++ / Python特有的)。 SIP支持回调甚至从C ++类继承Python类。
该工具非常强大,是PyQt绑定的引擎。
但请注意,Python中的可调用函数不仅仅是C ++中的函数,因为它可以包含上下文(它可以是闭包)。 在C ++代码中:
int callF(int (*f)(int, int), int a, int b) {
return f(a, b);
}
只能调用一个纯无上下文的函数,所以传递一般的Python回调是不可能的,因为没有足够的信息(唯一的解决方案是分配预编译的trampolines或在运行时生成C ++代码)。
如果你可以控制双方,但是解决方法是创建一个包含回调的C类并在Python中派生它。 例如:
struct CBack {
virtual int operator()(int x, int y) const {
return x+y;
}
virtual ~CBack() {}
};
int callF(const CBack& f,
int xv, int yv)
{
return f(xv, yv);
}
然后从CBack派生一个Python类并传递:
class Add(CBack):
def __call__(self, x, y):
return x + y
class Mul(CBack):
def __call__(self, x, y):
return x * y
print callF(Add(), 3, 7) # will print 10
print callF(Mul(), 3, 7) # will print 21
在这种情况下,你也可以传递一个(包裹的)lambda
def cback(f):
class PyCBack(CBack):
def __call__(self, x, y):
return f(x, y)
return PyCBack()
print callF(cback(lambda x, y: x*y), 3, 7)
换句话说,一个阻抗问题是C ++的函数与Python的函数不同(Python的函数也可以有上下文)。
可以从这里下载完整的示例。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.