Python SWIG:将C++返回参数转换为返回值,并将原始C++类型转换为Python类型

Python SWIG: convert C++ return parameter to return value, and convert raw C++ type to Python type

我试图修改现有的Sigg Python接口的C++库,添加Python包装更多的功能,我将非常感谢一些帮助来自一些有经验的SWIG。

具体来说,我正在处理一个带有如下签名的函数:

1
void execute(int x, double y, ResultType& result1, ResultType& result2);

此函数接受两个空的resultType对象,并将其作为输出参数填充。在python中,这必须转换为只接受xy的函数,然后返回result1result2的元组。

resultType是一种在整个库中广泛使用的容器类型。

类型映射(in)

从研究中,我认为我理解我需要为result1和result2添加一个类型映射"in",它吞没了参数并将它们保存到临时变量中。我还发现引用被swig转换成指针,因此&temp而不是temp。这是我的排版图"in":

1
2
3
4
5
6
7
typemap(in, numinputs=0) ResultType& result1 (ResultType temp) {
    $1 = &temp;
}

typemap(in, numinputs=0) ResultType& result2 (ResultType temp) {
    $1 = &temp;
}

打字机(AGOUT)

接下来,我添加了一个类型映射"argout",它将值附加到返回元组:

1
2
3
4
5
6
7
%typemap(argout) ResultType& result1 {
    $result = SWIG_Python_AppendOutput($result, temp$argnum);
}

%typemap(argout) ResultType& result2 {
    $result = SWIG_Python_AppendOutput($result, temp$argnum);
}

但是,这显然是行不通的,因为EDCOX1×6将是原始的C++类型EDCOX1×7,而我需要有一个EDCOX1×8,以便追加到元组。结果类型已经有一个有效的swig包装。所以,在python中,我可以调用ResultType()来构造它的一个实例,而不会产生任何问题。假设我走在正确的轨道上,我如何将原始C++ EDCOX1的7个对象转换为EDCOX1,8,属于EDCOX1×7的SWIG生成的包装器?(对不起,如果细节太多,我想避免"xy问题")。


就像$ 1是对输入类型映射中的Python输入对象的引用,1美元是对AdOutType映射中C++输出变量的引用。使用它,您可以为该数据生成一个python对象并将其附加到结果中。

以下是Windows的一个功能示例:

测试h

1
2
3
4
5
6
7
8
9
10
11
12
13
#ifdef EXPORT
#define API __declspec(dllexport)
#else
#define API __declspec(dllimport)
#endif

struct ResultType
{
    int x;
    double y;
};

API void execute(int x, double y, ResultType& result1, ResultType& result2);

测试程序

1
2
3
4
5
6
7
8
9
10
#define EXPORT
#include"test.h"

API void execute(int x, double y, ResultType& result1, ResultType& result2)
{
    result1.x = 2 * x;
    result1.y = 2 * y;
    result2.x = 3 * x;
    result2.y = 3 * y;
}

试验。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
%module test

%{
#include"test.h"
%}

%include <windows.i>

%typemap(in,numinputs=0) ResultType& %{
    // Create a persistent object to hold the result;
    $1 = new ResultType;
%}

%typemap(argout) ResultType& (PyObject* tmp) %{
    // Store the persistent object in a PyObject* that will be destroyed
    // when it goes out of scope.
    tmp = SWIG_NewPointerObj($1, $1_descriptor, SWIG_POINTER_OWN);
    $result = SWIG_Python_AppendOutput($result, tmp);
%}

%include"test.h"

产量

1
2
3
4
5
6
7
8
9
10
>>> import test
>>> r = test.execute(2,3)
>>> r[0].x
4
>>> r[0].y
6.0
>>> r[1].x
6
>>> r[1].y
9.0