如何使用 swig 将 c++ int** 返回值类型映射到 python

Posted

技术标签:

【中文标题】如何使用 swig 将 c++ int** 返回值类型映射到 python【英文标题】:how to typemap c++ int** return value to python with swig 【发布时间】:2018-05-28 07:02:19 【问题描述】:

下面是我的代码:

int** myfunction()

    int **value = new int*[4];
    for(int i=0;i<4;i++)
    
        value[i] = new int[4];
        memset(value[i], 0, 4*sizeof(int));
    
    // asign value

    return value;

然后我想调用myfunction 并使用python 列表返回int ** 类型值,所以我在我的.i 文件中添加了一个类型映射:

%typemap(out) int** 
    $result = PyList_New(4);
    for(int i=0;i<4;i++)
    
        PyObject *o = PyList_New(4);
        for(int j=0;j<4;j++)
        
            PyList_SetItem(o,j,PyInt_FromLong((long)$1[i][j]));
        
        PyList_SetItem($result, i, o);
    
    delete $1;

我在我的 python 代码中调用 myfunction 却什么也没得到。我的代码有什么不正确的地方?

【问题讨论】:

“无”是什么意思?您在 python 脚本中得到“无”?或者你得到一些零值?顺便说一句,SWIG 不支持指针运算,请参阅doc,第 5.3 节。我不确定您要在 python 脚本中做什么,但我希望您不能在 python 脚本中遍历数组。 result = myfunction() 在我的 python 中,然后我进行打印 print('result = ', result)。并没有打印任何内容。看起来我的 c++ 函数崩溃了,所以 print 没有运行。我正在尝试在我的 python 脚本中获取 c++ 函数的返回值。我不知道如何在python脚本中获取一个int**返回值。 【参考方案1】:

除了内存泄漏(只删除了外部的new 而不是内部的),您的代码看起来还不错。这是我所做的:

test.i

%module test

%typemap(out) int** 
    $result = PyList_New(4);
    for(int i=0;i<4;i++)
    
        PyObject *o = PyList_New(4);
        for(int j=0;j<4;j++)
        
            PyList_SetItem(o,j,PyInt_FromLong((long)$1[i][j]));
        
        delete [] $1[i];
        PyList_SetItem($result, i, o);
    
    delete [] $1;


%inline %
int** myfunction()

    int **value = new int*[4];
    for(int i=0;i<4;i++)
    
        value[i] = new int[4];
        for(int j=0;j<4;j++)
            value[i][j] = i*4+j;
    

    return value;

%

使用 SWIG 和 VS2015 编译器构建:

swig -c++ -python test.i
cl /EHsc /LD /W3 /MD /Fe_test.pyd /Ic:\python36\include test_wrap.cxx -link /libpath:c:\python36\libs

输出:

>>> import test
>>> test.myfunction()
[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]

【讨论】:

谢谢马克,你是对的,从 python 代码调用 c++ 函数会导致核心转储,这就是我的打印没有执行的原因。我是 swig 的新手,似乎“.i”文件只是另一种 c++ 头文件? @yellowfish no .i 文件是 swig 接口文件。 Swig 知道如何解析 c++ 并为 Python 等语言生成扩展代码。 .i 文件控制要解析的内容以及如何使用 % 指令生成代码。 是的,我明白了。我提供的代码创建了一个具有特定行长度和列长度的 int[][],但有时我不知道我的 python 代码中的行和列长度,是否有根据输入参数创建 int[][]? int** Function(int* row, int* col)*row = GetRow(); *col = GetCol(); //创建返回int[][]..... @yellowfish 将创建与输入参数联系起来并不简单。理想情况下,返回值应该是一个包含将其转换为 Python 对象所需的所有信息的结构,或者创建一组类型映射来处理 (int***,int x, int y) 并将函数转换为返回 @987654325 @ 作为输出参数而不是返回值。 好的,非常感谢您的帮助。在我的项目中,C++ 函数创建 int** 并将其作为输出返回给 python 调用者,只有 C++ 函数知道 int** 的大小,在这种情况下,我想也许我应该使用 std::vector 而不是 int** .@Mark Tolonen

以上是关于如何使用 swig 将 c++ int** 返回值类型映射到 python的主要内容,如果未能解决你的问题,请参考以下文章

使用 swig 类型映射从 c++ 方法返回向量<pair<int,int>> & 到 python 元组列表

使用 SWIG 时如何将 int 数组和 List<string> 作为参数从 C# 传递给 C++

如何使用 SWIG 将 numpy 数组转换为 vector<int>&(参考)

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

使用 SWIG 将 numpy 数组元素(int)传递给 c++ int

Python 的 C++ 扩展模块返回一个 Numpy 数组