【问题标题】:Python/SWIG: Output an arrayPython/SWIG:输出一个数组
【发布时间】:2017-02-02 17:41:36
【问题描述】:

我正在尝试从使用 SWIG for Python 包装的 C 函数输出值数组。我尝试做的方式是使用以下类型映射。

伪代码:

int oldmain() {
float *output = {0,1};
return output;
}

类型图:

%typemap(out) float* { 
   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); 
 } 
} 

我的代码编译得很好,但是当我运行访问这个函数时它挂起(没有更多的方法来调试它)。

对我哪里出错有什么建议吗?

谢谢。

【问题讨论】:

  • 您能分享您的 Makefile 或类似文件吗?你可能会发现 Cython 比 SWIG 更容易,除非你可能会做更多的语言而不仅仅是 Python。
  • 谢谢,Oleksiy 的回答解决了我的问题,但正如你所说,Cython 似乎更容易,我正在探索。再次感谢。

标签: python return-value swig


【解决方案1】:

允许长度变化的最简单方法是添加另一个输出参数,该参数也告诉您数组的大小:

%module test

%include <stdint.i>

%typemap(in,numinputs=0,noblock=1) size_t *len  {
  size_t templen;
  $1 = &templen;
}

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

%inline %{
float *oldmain(size_t *len) {
  static float output[] = {0.f, 1.f, 2, 3, 4};
  *len = sizeof output/sizeof *output;
  return output;
}
%}

这是从this answer 修改为添加size_t *len,可用于在运行时返回数组的长度。类型映射完全隐藏了 Python 包装器的输出,而是在 %typemap(out) 中使用它而不是固定大小来控制返回列表的长度。

【讨论】:

  • 感谢您的详细回复。我会试试这个。另一个问题:如果我的 C 代码中有一个变量或 #define 常量,这是我的输出数组长度,有没有办法在你的示例中使用它而不是“templen”?
  • @seu - 最简单的方法就是将其粘贴在 out 类型映射中以调用 PyList_Newfor 循环。
  • 它似乎不起作用:我尝试在我的 c 文件中定义一个常量,但出现以下错误 example_wrap.c:2980: error: ‘ARRLENGTH’ undeclared (first use in this function) 。我的意图是不再声明它,但以某种方式能够访问这个变量/常量。
  • @SEU - 您需要 类型映射之前执行 %{ #include "whatever.h" %} 以使 ARRLENGTH 的定义在生成的包装器中可见。
【解决方案2】:

这应该可以帮助您:

/* example.c */

float * oldmain() {
    static float output[] = {0.,1.};
    return output;
}

你在这里返回一个指针,swig 不知道它的大小。普通的 $1_dim0 是行不通的,所以你必须硬编码或做一些其他的魔法。像这样的:

/* example.i */
%module example
%{
 /* Put header files here or function declarations like below */
  extern float * oldmain();
%}

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

%include "example.c"

然后在python中你应该得到:

>> import example
>> example.oldmain()
[0.0, 1.0]

添加类型映射时,您可能会发现-debug-tmsearch 非常方便,即

swig -python -debug-tmsearch example.i

在为float *oldmain 寻找合适的“输出”类型映射时,应明确指出使用了您的类型映射。此外,如果您只是想访问 c 全局变量数组,您可以使用 varout 的类型映射来执行相同的技巧,而不仅仅是 out

【讨论】:

  • 嗨,非常感谢。这运作良好。我试图将它推广到任何长度的数组,所以我使用 $1_dim0 而不是“2”,我遇到了这个问题(也可以在文档 swig.org/Doc1.3/Typemaps.html#Typemaps_nn39 中找到)。 example_wrap.c:2979: error: ‘result_dim0’ undeclared (第一次在这个函数中使用)
  • @seu - 你不能这样做,因为数组的大小是未知的。返回类型是 float*,而不是 float[2],这是 $1_dim0 工作所必需的。
  • @Flexo。谢谢。我尝试在文档中使用 "%typemap(out) float [ANY] {" 并进行编译,但在 Python 中,我得到的返回值是 。本质上,我试图返回一个可变长度的数组。有没有办法做到这一点,还是我总是必须知道长度?
  • +1 用于 -debug-tmsearch;我有一个类似的问题,调试输出帮助我弄清楚我实际上想写一个 'argout' 类型图而不是 'out' 类型图
猜你喜欢
  • 1970-01-01
  • 2011-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-09
相关资源
最近更新 更多