python的swig typemap:输入和输出数组

Posted

技术标签:

【中文标题】python的swig typemap:输入和输出数组【英文标题】:swig typemap for python: input and output arrays 【发布时间】:2010-09-07 15:50:22 【问题描述】:

我有一个要在 Python 中使用的 C 函数:

extern int convertAtoB( stateStruct *myStruct,
                        const double PointA[3],
                        double PointB[3]);

使用 SWIG,我想我需要定义一个类型映射来转换两个点(PointA 是输入,PointB 是输出),以便 Python 可以使用它。 typemaps.i 中似乎没有适用于此的类型映射,因此我必须定义一个。我似乎在 SWIG 文档中找不到数组的示例。

我想像这样使用这个库:

s = externalStruct()
point_a = [1, 2, 3]
result, point_b = convertAtoB(s, point_a)
print point_b
"expect [4, 5, 6]"

我该怎么做?谢谢

【问题讨论】:

【参考方案1】:

你快到了。要摆脱 python 签名中的虚拟参数,您需要将 %typemap(in) for PointB[3] 更改为 %typemap(in,numinputs=0) 以指示 SWIG 忽略该输入值(无论如何您已经获取了它的副本)。这将从 python 方法签名中删除虚拟参数。

但是,我不确定您是否需要为该专业复制整个 %typemap(in)。可能有一种方法可以重用实际的类型图,但我不知道如何。否则你会得到一个额外的

%typemap(in,numinputs=0) double PointB[3] (double temp[$1_dim0]) 
  int i;
  if (!PySequence_Check($input)) 
    PyErr_SetString(PyExc_ValueError,"Expected a sequence");
    return NULL;
  
  if (PySequence_Length($input) != $1_dim0) 
    PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
    return NULL;
  
  for (i = 0; i < $1_dim0; i++) 
    PyObject *o = PySequence_GetItem($input,i);
    if (PyNumber_Check(o)) 
      temp[i] = (double) PyFloat_AsDouble(o);
     else 
      PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");      
      return NULL;
    
  
  $1 = temp;

【讨论】:

【参考方案2】:

这是我找到的一种解决方案,但它可能不是最好的:

%typemap(in) double[ANY] (double temp[$1_dim0]) 
  int i;
  if (!PySequence_Check($input)) 
    PyErr_SetString(PyExc_ValueError,"Expected a sequence");
    return NULL;
  
  if (PySequence_Length($input) != $1_dim0) 
    PyErr_SetString(PyExc_ValueError,"Size mismatch. Expected $1_dim0 elements");
    return NULL;
  
  for (i = 0; i < $1_dim0; i++) 
    PyObject *o = PySequence_GetItem($input,i);
    if (PyNumber_Check(o)) 
      temp[i] = (double) PyFloat_AsDouble(o);
     else 
      PyErr_SetString(PyExc_ValueError,"Sequence elements must be numbers");      
      return NULL;
    
  
  $1 = temp;

这是我最终遇到的将 Python 列表转换为数组的文档中的一个示例。下一部分更难,拼凑几个例子,我可以将返回数组转换为 python 列表:

%typemap(argout) double PointB[3]
    PyObject *o = PyList_New(3);
    int i;
    for(i=0; i<3; i++)
    
        PyList_SetItem(o, i, PyFloat_FromDouble($1[i]));
    
    $result = o;

但是,我必须为 API 中的每个返回值创建一个。另外我必须用一个虚拟值作为参数来调用它:

point_b = convertAtoB(s, point_a, dummy)

有没有更好的办法?

【讨论】:

【参考方案3】:

这是一个旧线程,但我回答它是因为没有太多关于 SWIG 的帖子得到回答。

专门针对上述情况

%typemap(in, numinputs=0) double PointB[3] 
  double tmp[3];
  $1 = tmp;


%typemap(argout) double PointB[3] 
  PyObject *o = PyList_New(3);
  int i;
  for(i=0; i<3; i++)
  
    PyList_SetItem(o, i, PyFloat_FromDouble($1[i]));
  
  $result = o;

【讨论】:

以上是关于python的swig typemap:输入和输出数组的主要内容,如果未能解决你的问题,请参考以下文章

将 C++ 字符串类转换为 Python 字符串

SWIG——在扩展内使用类型映射

在 Linux 中使用 SWIG for Python 转换字符串

在 swig 上包装返回向量<T>

Python - 类型图中的 SWIG 不起作用

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