Wrap C结构与数组成员一起访问Python:Swig? Cython? ctypes?[英] Wrap C struct with array member for access in python: SWIG? cython? ctypes?

本文是小编为大家收集整理的关于Wrap C结构与数组成员一起访问Python:Swig? Cython? ctypes?的处理方法,想解了Wrap C结构与数组成员一起访问Python:Swig? Cython? ctypes?的问题怎么解决?Wrap C结构与数组成员一起访问Python:Swig? Cython? ctypes?问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我想访问一个C函数,该C函数从Python返回包含双阵列的结构(这些阵列的长度由其他INT成员给出).声明为

typedef struct {
  int dim;
  int vertices;
  int quadrature_degree;
  int polynomial_degree;
  int ngi;
  int quadrature_familiy;
  double *weight; /* 1D: ngi */
  double *l;      /* 2D: ngi * dim */
  double *n;      /* 2D: ngi * vertices */
  double *dn;     /* 3D: ngi * vertices * dim */
} element;

extern void get_element(int dim, int vertices, int quad_degree, int poly_degree, element* e);

重要的一点是,我希望能够作为正确形状的numpy数组访问所有double*成员(即dn应该是3D数组).

简单地包装它可以使我的结构很好,但是所有double*成员都是<Swig Object of type 'double *' at 0x348c8a0>,这使它们无用.我玩了Numpy Swig界面文件,但无法获得任何类型( DATA_TYPE* INPLACE_ARRAY1, int DIM1 )工作(我认为在这种情况下不可能让它们匹配,但我很高兴被证明是错误的).

我的猜测是,我必须将numpy阵列的代码初始化为这些成员的PyArrayObject,而swig扩展了我的结构以使它们在python中访问?这看起来像是很多工作.有人可以使用SWIG看到更好的方式吗?如果使事情变得更容易,则可以更改结构或返回的方法.

或者,我看了看Cython和CTYPES.这些会更适合我要实现的目标吗?我没有使用Cython,所以不能判断它的包装功能.对于CTYPES,我可以粗略地想象该怎么做,但这意味着我希望有合理自动化的包装器可以为我做的事情.

感激不尽收到的任何建议!

推荐答案

使用SWIG需要为整个结构进行打字.仅用于指针成员的Tyepmaps不够,因为它们没有上下文来知道使用Numpy阵列的大小.我设法通过以下类型获得了我想要的东西(基本上是从numpy.i复制和粘贴,并且适应我的需求,可能不是很健壮):

%typemap (in,numinputs=0) element * (element temp) {
  $1 = &temp;
}

%typemap (argout) element * {
  /* weight */
  {
    npy_intp dims[1] = { $1->ngi };
    PyObject * array = PyArray_SimpleNewFromData(1, dims, NPY_DOUBLE, (void*)($1->weight));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
  /* l */
  {
    npy_intp dims[2] = { $1->ngi, $1->dim };
    PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (void*)($1->l));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
  /* n */
  {
    npy_intp dims[2] = { $1->ngi, $1->vertices };
    PyObject * array = PyArray_SimpleNewFromData(2, dims, NPY_DOUBLE, (void*)($1->n));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
  /* dn */
  {
    npy_intp dims[3] = { $1->ngi, $1->vertices, $1->dim };
    PyObject * array = PyArray_SimpleNewFromData(3, dims, NPY_DOUBLE, (void*)($1->dn));
    if (!array) SWIG_fail;
    $result = SWIG_Python_AppendOutput($result,array);
  }
}

这与C函数不同,因为它返回了带有我想要的数据的numpy数组元组,这比稍后必须从element对象提取它更方便.此外,第一个Typemap消除了传递类型element对象的需求.因此,我可以完全从Python用户隐藏element struct.

Python接口最终看起来像这样:

weight, l, n, dn = get_element(dim, vertices, quadrature_degree, polynomial_degree)

其他推荐答案

Cython规则:

cdef extern from "the header.h":

ctypedef struct element:
  int dim
  int vertices
  int quadrature_degree
  int polynomial_degree
  int ngi
  int quadrature_familiy
  double *weight
  double *l
  double *n
  double *dn

void get_element(int dim, int vertices, int quad_degree, int poly_degree, element* e)

然后您可以从Python Space

接口它

其他推荐答案

查看Swig的打字.他们让您编写自己的代码来处理特定类型,特定实例(类型+名称)甚至参数组.我没有为结构做到这一点,但是要特别处理C功能采用数组及其大小的情况:

%typemap(in) (int argc, Descriptor* argv) {
    /* Check if is a list */
    if (PyList_Check($input)) {
        int size = PyList_Size($input);
        $1 = size;
        ...
        $2 = ...;
    }
}

将采用两对参数int argc, Descriptor* argv(由于提供了名称,也必须匹配),然后传递您所使用的pyobject,然后您编写需要进行转换的任何C代码.您可以使用numpy c api进行转换.

本文地址:https://www.itbaoku.cn/post/359215.html