Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/59.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
将C库与Python接口的SWIG(从C';序列';结构创建&';Python数据类型)_Python_C_Swig - Fatal编程技术网

将C库与Python接口的SWIG(从C';序列';结构创建&';Python数据类型)

将C库与Python接口的SWIG(从C';序列';结构创建&';Python数据类型),python,c,swig,Python,C,Swig,我已经为C库编写了Python扩展。我的数据结构如下所示: typedef struct _mystruct{ double * clientdata; size_t len; } MyStruct; 此数据类型的用途直接映射到Python中的列表数据类型。因此,我希望为导出的结构创建“类似列表”的行为,以便使用我的C扩展编写的代码更“Pythonic” 特别是,这是我希望能够做到的(来自python代码) 注意:py_ctsruct是在python中访问的ctsruct数据类

我已经为C库编写了Python扩展。我的数据结构如下所示:

typedef struct _mystruct{
   double * clientdata;
   size_t   len;
} MyStruct;
此数据类型的用途直接映射到Python中的列表数据类型。因此,我希望为导出的结构创建“类似列表”的行为,以便使用我的C扩展编写的代码更“Pythonic”

特别是,这是我希望能够做到的(来自python代码) 注意:py_ctsruct是在python中访问的ctsruct数据类型

我的要求可以概括为:

  • list(py_ctsruct)返回一个python列表,其中包含从c结构复制的所有内容
  • py_cstruct[i]返回第i个元素(最好在无效索引上抛出indexer)
  • 对于py_ctsruct中的元素:枚举能力
  • 根据,如果一个对象实现了 _iter()或_getitem()。使用这种逻辑,我认为通过将以下属性(via)添加到我的SWIG接口文件中,我将获得所需的行为(除了上面的req.#1,我仍然不知道如何实现):

    现在我可以用python为C对象编制索引了。我还没有实现Python异常抛出,但是如果超出数组边界,将返回一个幻数(错误代码)

    有趣的是,当我尝试使用“for x in”语法迭代结构时,例如:

    for i in py_cstruct:
        print i
    
    Python进入一个无限循环,在控制台上只打印上面提到的神奇(错误)数字。这对我来说意味着索引有问题

    最后但并非最不重要的一点,我如何实现需求1?这包括(据我所知):

    • 处理python中的函数调用list()
    • 从C代码返回Python(列表)数据类型
    [[Update]]

    我希望看到一些关于我需要在接口文件中放入什么(如果有的话)声明的代码片段,这样我就可以从Python中迭代c结构的元素

  • 使用%typemap swig命令查找。 http://www.swig.org/Doc2.0/SWIGDocumentation.html#Typemaps_nn25 typemap中的memberin可能会执行您想要的操作。 我在Python部分找到了一个类型映射,它允许我将char **数据作为一个Python字符串列表传递到C++中。我猜会有类似的功能
  • 此外,您还可以在swig“i”文件的结构内的接口中定义%pythoncode。这将允许您在为结构创建的对象中添加python方法。还有另一个命令%addmethod(我想)允许您将方法添加到结构或类中。然后,如果需要,可以创建用于在C++或C中索引对象的方法。有很多方法可以解决这个问题

  • 对于我正在处理的一个接口,我使用了一个类对象,它有一些方法来访问代码中的数据。这些方法是用C++编写的。然后,在“I”文件内部的类中使用了%python代码指令,在Python代码中创建了“<强> GestITE<强>”和“<强> SeTiTEM <强> >方法,使用EnguleC++方法使其看起来像字典式访问。

    您说您还没有实现Python异常抛出-这就是问题所在。从政治公众人物234:

    定义了一个新的异常StopIteration,它可以用来发出迭代结束的信号

    您必须在迭代结束时设置此异常。由于您的代码没有做到这一点,因此您遇到了您描述的情况:

  • 解释器在列表的自定义
    iternext
    函数中循环
  • 您的函数到达数组的末尾,而不是正确设置
    StopIteration
    异常,而是简单地返回您的“幻数”
  • 解释器没有看到停止迭代的好理由,只是继续打印
    iternext
    返回的值。。。你的神奇数字。对于口译员来说,这只是另一个列表成员
  • 幸运的是,这是一个非常简单的修复方法,尽管看起来可能不那么简单,因为C没有异常功能。Python C API只是使用一个全局错误指示符,在出现异常情况时设置该指示符,然后API标准指示您在堆栈上向解释器返回NULL,解释器然后查看
    PyErr_occurrent()
    的输出以查看是否设置了错误,以及是否设置了错误,打印相关的异常和回溯

    因此,在函数中,当到达数组末尾时,您只需要:

    PyErr_SetString(PyExc_StopIteration,"End of list");
    return NULL;
    

    下面是关于这个问题的另一个很好的答案:

    解决这个问题的最简单方法是实现一个无效索引并抛出一个异常

    我举了一个例子,在SWIG中使用
    %extend
    %exception
    分别实现
    \uu getitem\uuuuuuuuu
    和引发异常:

    %module test
    
    %include "exception.i"
    
    %{
    #include <assert.h>
    #include "test.h"
    static int myErr = 0; // flag to save error state
    %}
    
    %exception MyStruct::__getitem__ {
      assert(!myErr);
      $action
      if (myErr) {
        myErr = 0; // clear flag for next time
        // You could also check the value in $result, but it's a PyObject here
        SWIG_exception(SWIG_IndexError, "Index out of bounds");
      }
    }
    
    %include "test.h"
    
    %extend MyStruct {
      double __getitem__(size_t i) {
        if (i >= $self->len) {
          myErr = 1;
          return 0;
        }
        return $self->clientdata[i];
      }
    }
    
    其中打印:

    python run.py
    0.0
    1.0
    2.0
    3.0
    4.0
    5.0
    6.0
    7.0
    8.0
    9.0
    
    然后结束


    另一种方法是使用typemap将
    MyStruct
    直接映射到
    PyList
    上:

    %module test
    
    %{
    #include "test.h"
    %}
    
    %typemap(out) (MyStruct *) {
      PyObject *list = PyList_New($1->len);
      for (size_t i = 0; i < $1->len; ++i) {
        PyList_SetItem(list, i, PyFloat_FromDouble($1->clientdata[i]));
      }
    
      $result = list;
    }
    
    %include "test.h"
    

    对于像链表这样的容器,使用迭代器更有意义,但为了完整性起见,下面是使用
    \uu iter\uu
    MyStruct
    执行迭代器的方法。关键是让SWIG为您包装另一种类型,它提供了所需的
    \uuuu iter\uuuu()
    next()
    ,在这种情况下
    MyStructIter
    使用
    %inline
    同时定义和包装,因为它不是普通C API的一部分:

    %module test
    
    %include "exception.i"
    
    %{
    #include <assert.h>
    #include "test.h"
    static int myErr = 0;
    %}
    
    %exception MyStructIter::next {
      assert(!myErr);
      $action
      if (myErr) {
        myErr = 0; // clear flag for next time
        PyErr_SetString(PyExc_StopIteration, "End of iterator");
        return NULL;
      }
    }
    
    %inline %{
      struct MyStructIter {
        double *ptr;
        size_t len;
      };
    %}
    
    %include "test.h"
    
    %extend MyStructIter {
      struct MyStructIter *__iter__() {
        return $self;
      }
    
      double next() {
        if ($self->len--) {
          return *$self->ptr++;
        }
        myErr = 1;
        return 0;
      }
    }
    
    %extend MyStruct {
      struct MyStructIter __iter__() {
        struct MyStructIter ret = { $self->clientdata, $self->len };
        return ret;
      }
    }
    
    (在本例中,我们实际上可以使用容器本身作为迭代器作为迭代器,方法是提供一个
    \uuu iter\uuuu()
    ,返回容器的副本和一个
    next()
    
    python run.py
    0.0
    1.0
    2.0
    3.0
    4.0
    5.0
    6.0
    7.0
    8.0
    9.0
    
    %module test
    
    %{
    #include "test.h"
    %}
    
    %typemap(out) (MyStruct *) {
      PyObject *list = PyList_New($1->len);
      for (size_t i = 0; i < $1->len; ++i) {
        PyList_SetItem(list, i, PyFloat_FromDouble($1->clientdata[i]));
      }
    
      $result = list;
    }
    
    %include "test.h"
    
    %typemap(in) (MyStruct *) {
      if (!PyList_Check($input)) {
        SWIG_exception(SWIG_TypeError, "Expecting a PyList");
        return NULL;
      }
      MyStruct *tmp = malloc(sizeof(MyStruct));
      tmp->len = PyList_Size($input);
      tmp->clientdata = malloc(sizeof(double) * tmp->len);
      for (size_t i = 0; i < tmp->len; ++i) {
        tmp->clientdata[i] = PyFloat_AsDouble(PyList_GetItem($input, i));
        if (PyErr_Occured()) {
          free(tmp->clientdata);
          free(tmp);
          SWIG_exception(SWIG_TypeError, "Expecting a double");
          return NULL;
        }
      }
      $1 = tmp;
    }
    
    %typemap(freearg) (MyStruct *) {
      free($1->clientdata);
      free($1);
    }
    
    %module test
    
    %include "exception.i"
    
    %{
    #include <assert.h>
    #include "test.h"
    static int myErr = 0;
    %}
    
    %exception MyStructIter::next {
      assert(!myErr);
      $action
      if (myErr) {
        myErr = 0; // clear flag for next time
        PyErr_SetString(PyExc_StopIteration, "End of iterator");
        return NULL;
      }
    }
    
    %inline %{
      struct MyStructIter {
        double *ptr;
        size_t len;
      };
    %}
    
    %include "test.h"
    
    %extend MyStructIter {
      struct MyStructIter *__iter__() {
        return $self;
      }
    
      double next() {
        if ($self->len--) {
          return *$self->ptr++;
        }
        myErr = 1;
        return 0;
      }
    }
    
    %extend MyStruct {
      struct MyStructIter __iter__() {
        struct MyStructIter ret = { $self->clientdata, $self->len };
        return ret;
      }
    }
    
    %inline %{
      struct MyStructIter {
        MyStruct *list;
        size_t pos;
      };
    %}
    
    %include "test.h"
    
    %extend MyStructIter {
      struct MyStructIter *__iter__() {
        return $self;
      }
    
      double next() {
        if ($self->pos < $self->list->len) {
          return $self->list->clientdata[$self->pos++];
        }
        myErr = 1;
        return 0;
      }
    }
    
    %extend MyStruct {
      struct MyStructIter __iter__() {
        struct MyStructIter ret = { $self, 0 };
        return ret;
      }
    }
    
    %ignore MyStructIter::atEnd();
    %exception MyStructIter::next {
        if( $self->list->atEnd() ) {
            PyErr_SetString(PyExc_StopIteration,"End of list");
            SWIG_fail;
        }
        $action
    }
    
    %exception MyStructIter::next {
        if( $self->pos >= $self->list->len ) {
            PyErr_SetString(PyExc_StopIteration,"End of list");
            SWIG_fail;
        }
        $action
    }
    
    %rename(__next__) MyStructIter::next;