gpt4 book ai didi

python - 通过 SWIG 传递函数指针数组

转载 作者:塔克拉玛干 更新时间:2023-11-03 02:15:23 25 4
gpt4 key购买 nike

https://stackoverflow.com/a/22965961/353337的帮助下,我能够创建一个简单的示例,说明如何通过 Python 将一个函数指针传递给一个函数。具体来说,与

double f(double x) {
return x*x;
}

double myfun(double (*f)(double x)) {
fprintf(stdout, "%g\n", f(2.0));
return -1.0;
}
%module test

%{
#include "test.hpp"
%}

%pythoncallback;
double f(double);
%nopythoncallback;

%ignore f;
%include "test.hpp"

我可以打电话

import test
test.f(13)
test.myfun(test.f)

并得到预期的结果。

现在,我想更改 myfun 的签名以允许函数指针的数组(都具有相同的签名),例如,

double myfun(std::vector<double (*)(double)>)

如何调整 .i 文件?

理想情况下,Python 调用将通过列表

test.myfun([test.f, test.g])

最佳答案

我制作了以下测试用例来说明您要执行的操作。它有一个真正的实现 myfun(const std::vector<double(*)(double)>&)让生活更有趣一点:

#include <vector>

double g(double x) {
return -x;
}

double f(double x) {
return x*x;
}

typedef double(*pfn_t)(double);

std::vector<double> myfun(const std::vector<pfn_t>& funs, const double d) {
std::vector<double> ret;
ret.reserve(funs.size());
for(auto && fn : funs)
ret.emplace_back(fn(d));
return ret;
}

我希望我们需要做的就是使用:

%include <std_vector.i>
%template(FunVec) std::vector<double(*)(double)>;
%template(DoubleVec) std::vector<double>;
%include "test.h"

但是 SWIG 3.0(来自 Debian 稳定版)不处理这个 FunVec正确并且生成的模块无法编译。所以我添加了一个类型映射作为解决方法:

%module test

%{
#include "test.h"
%}

%pythoncallback;
double f(double);
double g(double);
%nopythoncallback;

%ignore f;
%ignore g;

%typemap(in) const std::vector<pfn_t>& (std::vector<pfn_t> tmp) {
// Adapted from: https://docs.python.org/2/c-api/iter.html
PyObject *iterator = PyObject_GetIter($input);
PyObject *item;

if (iterator == NULL) {
assert(iterator);
SWIG_fail; // Do this properly
}

while ((item = PyIter_Next(iterator))) {
pfn_t f;
const int res = SWIG_ConvertFunctionPtr(item, (void**)(&f), $descriptor(double(*)(double)));
if (!SWIG_IsOK(res)) {
assert(false);
SWIG_exception_fail(SWIG_ArgError(res), "in method '" "foobar" "', argument " "1"" of type '" "pfn_t""'");
}
Py_DECREF(item);
tmp.push_back(f);
}

Py_DECREF(iterator);
$1 = &tmp;
}

%include <std_vector.i>
// Doesn't work:
//%template(FunVec) std::vector<double(*)(double)>;
%template(DoubleVec) std::vector<double>;
%include "test.h"

基本上所有这些所做的就是为函数指针类型的 vector 添加一个“输入”类型映射。该类型映射只是迭代 Python 给出的输入并构建一个临时的 std::vector来自 Python 可迭代对象。

这足以让以下 Python 按预期工作:

import test

print test.g
print test.f
print test.g(666)
print test.f(666)

print test.myfun([test.g,test.f],123)

关于python - 通过 SWIG 传递函数指针数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39046704/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com