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

Posted

技术标签:

【中文标题】Python SWIG:将 C++ 返回参数转换为返回值,并将原始 C++ 类型转换为 Python 类型【英文标题】:Python SWIG: convert C++ return parameter to return value, and convert raw C++ type to Python type 【发布时间】:2018-03-05 23:49:10 【问题描述】:

我正在尝试为 C++ 库修改现有的 SWIG Python 接口,为更多功能添加 Python 包装器,非常感谢有 SWIG 经验的人提供的帮助。

具体来说,我正在开发一个具有这样签名的函数:

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

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

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

typemap(in)

从研究中,我想我明白我需要为 result1 和 result2 添加一个类型映射“in”,它会吞下参数并将它们保存到临时变量中。我还发现引用被 SWIG 转换为指针,因此 &temp 而不是 temp。这是我的“输入”类型图:

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


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

类型映射(参数)

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

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


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

但是,这显然行不通,因为temp$argnum 将是原始C++ 类型ResultType,而我需要PyObject * 才能附加到元组。 ResultType 已经有一个有效的 SWIG 包装器。因此,在 Python 中,我可以毫无问题地调用 ResultType() 来构造它的实例。假设到目前为止我走在正确的轨道上,如何将原始 C++ ResultType 对象转换为属于 SWIG 生成的 ResultType 包装器的 PyObject *? (对不起,如果太多细节,我试图避免“XY问题”)

【问题讨论】:

【参考方案1】:

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

这是一个适用于 Windows 的功能示例:

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

#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

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

输出

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

【讨论】:

你的小例子效果很好!谢谢!这是我错过的魔法咒语……SWIG_NewPointerObj($1, $1_descriptor, SWIG_POINTER_OWN);

以上是关于Python SWIG:将 C++ 返回参数转换为返回值,并将原始 C++ 类型转换为 Python 类型的主要内容,如果未能解决你的问题,请参考以下文章

如何在 SWIG 中将向量的锯齿状 C++ 向量转换(类型映射)为 Python

SWIG:将其参数从 c++ 修改为 python 的函数

类型映射资源并将列表转换为矢量(和返回)

如何使用 Swig 将 unsigned char* 转换为 Python 列表?

如何使用 swig 将 python 类实例作为 c++ 函数的参数传递?

使用 SWIG 将 C++ 对象指针传递给 Python,而不是再次返回 C++