Swig返回双精度数组

9 投票
5 回答
10824 浏览
提问于 2025-04-16 16:36

我知道,解决某些问题的方法通常有很多种。但是在这里,我知道我想要的方式,但我在用Python和SWIG时却无法让它工作...

我有一个C语言的函数,它返回一个双精度浮点数的数组:

double *my(int x)
{
   double a,b,*buf;
   buf = malloc (x * sizeof(double));
   a=3.14;
   b=2.7;
   buf[0]=a;
   buf[1]=b;
   return buf;
}

在这里,我确实想要这个数组作为返回值。不是像很多例子那样的“void”函数,它只是往一个输入数组里写数据。现在,我想要一个SWIG的Python封装,可以像这样使用:

>>> import example
>>> print example.my(7)
[3.14,2.7]

无论我怎么做,我在这里总是遇到一些概念上的问题——我总是得到类似 <Swig Object of type 'double *' at 0xFABCABA12> 的东西。

我尝试在我的swg文件中定义一些类型映射:

%typemap(out) double [ANY] {
  int i;
  $result = PyList_New($1_dim0);
  for (i = 0; i < $1_dim0; i++) {
    PyObject *o = PyFloat_FromDouble((double) $1[i]);
    PyList_SetItem($result,i,o);
  }
}

但我仍然无法得到我想要的结果。有没有人能提供一个简单的代码示例来完成这个任务?

5 个回答

1

你可能想看看关于carray.i的文档:

%include "carrays.i" %array_class(int, intArray);

http://www.swig.org/Doc2.0/Python.html#Python_nn48

3

我遇到过类似的问题,以下是我解决的办法。

// example.i

%module example

%include "carrays.i"
%array_class(float, floatArray);

float * FloatArray(int N);

float SumFloats(float * f);

 

# ipython

> a = example.floatArray(23) # array generated by swig's class constructor

> a

<example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e74180> >

> a[0]

-2.6762280573445764e-37 # unfortunately it is created uninitialized..

> b = example.FloatArray(23) # array generated by function

> b

<Swig Object of type 'float *' at 0x2e6ad80>

> b[0]
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
# .....
TypeError: 'SwigPyObject' object is not subscriptable

> #But there is a way to access b!!

> p = example.floatArray_frompointer(b) # i found this function by example. and twice tab

> p

<example.floatArray; proxy of <Swig Object of type 'floatArray *' at 0x2e66750> >

> p[0]

0.0

> p[0] = 42

> p[0]

42.0

幸运的是,这些类型(float *、floatArray * 和 floatArray * 的代理)都可以顺利地传递给 C++ 函数(比如 SumFloats)。

4

第一个问题是你的类型映射不匹配。你需要一个 %typemap(out) double * { ... },因为你的函数返回的是一个指向双精度浮点数的指针,而不是一个双精度数组。

如果你的列表是固定大小的(也就是一个整数常量),就像你给出的例子那样(我猜这不是你想要的),你可以简单地按照我上面说的更改类型映射,并把 $1_dim0 替换为固定的大小。

否则,你的问题在于你的 %typemap(out) double * 根本无法知道你的参数 int x 的值。你可以返回一个结构体,里面同时包含指针和大小。这样你就可以轻松定义一个类型映射,把它转成一个列表(或者NumPy数组,具体可以参考我对 如何用SWIG、Cython或ctypes在Python中访问C结构体的数组成员的回答)。

顺便提一下,在C语言中返回固定大小的数组是不可能的(可以参考这个回答: 声明一个C函数返回数组),所以 %typemap(out) double [ANY] { ... } 永远无法匹配。

撰写回答