简体   繁体   English

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

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

I'm trying to modify an existing SWIG Python interface for a C++ library, to add Python wrappers for more functions, and I would greatly appreciate some help from someone experienced with SWIG. 我正在尝试为C ++库修改现有的SWIG Python接口,以添加Python包装器以实现更多功能,并且非常感谢SWIG经验丰富的人员提供的帮助。

Specifically I'm working on a function with a signature like this: 具体来说,我正在使用具有以下特征的函数:

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

This function accepts two empty ResultType objects and fills them in as a output parameters. 此函数接受两个空的ResultType对象,并将其填充为输出参数。 In Python, this has to translate to a function that takes only x and y , then returns a tuple of result1 and result2 . 在Python中,这必须转换为仅包含xy的函数,然后返回result1result2的元组。

ResultType is a container type that is used widely throughout the library. ResultType是在整个库中广泛使用的容器类型。

typemap(in) 类型表(中)

From research, I think I understand that I need to add a typemap "in" for result1 and result2, which swallows the arguments and saves them to temporary variables. 通过研究,我认为我了解我需要为result1和result2添加一个“在”中的类型映射,该映射将吞入参数并将其保存为临时变量。 I also found that the reference is converted to a pointer by SWIG, hence &temp instead of temp . 我还发现该引用由SWIG转换为指针,因此&temp而不是temp Here is my typemap "in": 这是我的类型图“中”:

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

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

typemap(argout) 类型表(argout)

Next, I added a typemap "argout" that appends the values to a return tuple: 接下来,我添加了一个类型映射“ argout”,将值附加到返回元组:

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

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

However, this obviously won't work, because temp$argnum will be of the raw C++ type ResultType , whereas I need to have a PyObject * in order to append to a tuple. 但是,这显然是行不通的,因为temp$argnum将是原始C ++类型的ResultType ,而我需要有一个PyObject *才能附加到元组。 ResultType already has a working SWIG wrapper. ResultType已经具有可用的SWIG包装器。 So, in Python I can call ResultType() to construct an instance of it without a problem. 因此,在Python中,我可以调用ResultType()来构造它的实例,而不会出现问题。 Assuming that I am on the right track so far, how do I convert the raw C++ ResultType object to a PyObject * belonging to the SWIG-generated wrapper for ResultType ? 假设到目前为止我ResultType正确的轨道上,如何将原始C ++ ResultType对象转换为属于ResultType生成的ResultType包装器的PyObject * (Sorry if too much detail, I'm trying to avoid the "XY Problem") (很抱歉,如果细节过多,我正试图避免出现“ XY问题”)

Just like $1 is a reference to the Python input object in the input typemap, $1 is a reference to the C++ output variable in the argout typemap. 就像$ 1是对输入类型图中的Python输入对象的引用一样,$ 1是对argout类型图中的C ++输出变量的引用。 Using this, you can generate a Python object for that data and append it to the result. 使用此方法,您可以为该数据生成一个Python对象,并将其附加到结果中。

Here's a functional example for Windows: 这是Windows的功能示例:

test.h test.h

#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);

test.cpp TEST.CPP

#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;
}

test.i test.i

%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"

Output 产量

>>> 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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM