从 swig 返回 double * 作为 python 列表
Posted
技术标签:
【中文标题】从 swig 返回 double * 作为 python 列表【英文标题】:return double * from swig as python list 【发布时间】:2012-12-25 19:22:52 【问题描述】:我有一个 C++ 类,其中一个方法返回一个类似 double *
的数组,这是它的成员变量之一。我试图让它作为 Python 中的列表访问。我将它包装在doubleArray_frompointer
中,然后尝试使用 deepcopy 将其安全地从那里取出,但是当doubleArray
超出范围时我仍然遇到问题,它的内存被清理,然后 C++ 类尝试清理相同的内存(尽管我创建的gist 中没有显示)。
我怀疑我应该使用类型映射来执行此操作。
我要包装的是:
double *foo()
double *toReturn = new double[2];
toReturn[0] = 2;
toReturn[1] = 4;
return toReturn;
界面是:
%module returnList
%include "returnList.h"
%include "cpointer.i"
%pointer_functions(double, doubleP)
%include "carrays.i"
%array_class(double, doubleArray);
%
#include "returnList.h"
%
【问题讨论】:
“类型映射通常不是使用 SWIG 的必需部分。”也许我在这里遗漏了一些明显的东西? 【参考方案1】:您说的正确,可以使用类型映射来避免在 Python 端编写循环。我举了一个例子——它和this other answer非常相似。
%module test
%typemap(out) double *foo %
$result = PyList_New(2); // use however you know the size here
for (int i = 0; i < 2; ++i)
PyList_SetItem($result, i, PyFloat_FromDouble($1[i]));
delete $1; // Important to avoid a leak since you called new
%
%inline %
double *foo()
double *toReturn = new double[2];
toReturn[0] = 2;
toReturn[1] = 4;
return toReturn;
%
这里的类型映射匹配一个名为 foo
的函数返回 double *
- 你可以匹配更广泛,但是对于返回 double *
并不意味着你正在返回的函数会有做错事情的风险一个大小为 2 的数组。
有了这个类型图,我就可以运行了:
Python 2.6.6 (r266:84292, Dec 27 2010, 00:02:40)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> test.foo()
[2.0, 4.0]
>>>
您需要像这样手动编写它的原因是因为 SWIG 无法推断您从 foo
返回的数组的长度。它甚至可能因调用而异。
【讨论】:
它会因调用而异,但该长度numRounds
是程序参数之一。也就是说,它是一个我们可以在 Python 中访问的变量(大约 200 个)。这是否意味着我应该在 Python 中使用循环?但是,不知何故,我仍然必须在 swig 接口文件或我的 C++ 代码中写入 new
,以便 Python 和 C++ 类都不会尝试清理相同的内存。
gist 过于简单化了。我正在返回一个类成员,而不仅仅是从一个函数中。现在已修复,但它没有给出我希望的错误。
我认为这是所问问题的正确答案。但是,我真的应该使用 std::vector我不是通过返回任何类型的向量或数组对象来“解决”这个问题,而是通过在 Python 中重新创建最初生成数组的(简单)循环。也就是说,我的 C++ 代码只需返回单个双精度值,而我的 Python 代码将组装这个列表。
更明确地说,我有 C++ 方法double *simulation.run()
,这会造成麻烦。我创建了一个新的 C++ 方法 double simulation.doRound()
,然后通过 SWIG 在 numRounds
迭代的 Python 循环中调用它,每次迭代都执行 outputs.append(simulation.doRound())
。
但是,我仍然想知道如何通过 SWIG 将 C/C++ double *
数组复制到 Python 列表,因为这似乎是一个基本操作。如果有人可以回答,我会标记为已接受的答案。
【讨论】:
以上是关于从 swig 返回 double * 作为 python 列表的主要内容,如果未能解决你的问题,请参考以下文章
SWIG:将 2d numpy 数组传递给 C 函数 f(double a[])
如何使用 swig 从`unsigned int *`返回`uint []`