SWIG 将 C 库连接到 Python(从 C“序列”结构创建“可迭代”Python 数据类型)

2024-04-22

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

typedef struct _mystruct{
   double * clientdata;
   size_t   len;
} MyStruct;

此数据类型的用途直接映射到 Python 中的列表数据类型。因此,我想为导出的结构创建“类似列表”的行为,以便使用我的 C 扩展编写的代码更加“Pythonic”。

特别是,这就是我想要做的(来自 python 代码) 注意:py_ctsruct 是在 python 中访问的 ctsruct 数据类型。

我的要求可以概括为:

  1. list(py_ctsruct) 返回一个 python 列表,其中所有内容都从 c 结构中复制出来
  2. py_cstruct[i] 返回ith元素(最好在无效索引上抛出 IndexError )
  3. 对于 py_ctsruct 中的 elem:枚举能力

根据PEP234 http://www.python.org/dev/peps/pep-0234/, 如果对象实现了,则可以使用“for”对其进行迭代 _iter_() or _getitem_()。然后使用该逻辑,我认为通过添加以下属性(通过rename http://www.swig.org/Doc1.3/SWIG.html#SWIG_rename_ignore)到我的 SWIG 接口文件,我将具有所需的行为(除了上面的 req.#1 - 我仍然不知道如何实现):

__len__
__getitem__
__setitem__

我现在可以在 python 中索引 C 对象。我还没有实现 Python 异常抛出,但是如果超出数组范围,则会返回一个幻数(错误代码)。

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

for i in py_cstruct:
    print i

Python 进入一个无限循环,仅在控制台上打印上面提到的幻数(错误)。这对我来说表明索引有问题。

最后但并非最不重要的一点是,如何实现要求 1?这涉及(据我了解):

  • 处理函数调用list()来自蟒蛇
  • 从 C 代码返回 Python(列表)数据类型

[[更新]]

我有兴趣查看一些关于我需要在接口文件中放入哪些(如果有)声明的代码片段,以便我可以从 Python 迭代 c 结构的元素。


最简单的解决方案是实施__getitem__ http://docs.python.org/reference/datamodel.html#object.__getitem__并抛出一个IndexError http://docs.python.org/library/exceptions.html#exceptions.IndexError无效索引的异常。

我整理了一个例子,使用%extend and %exception在 SWIG 中实施__getitem__并分别引发异常:

%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];
  }
}

我通过添加到 test.h 来测试它:

static MyStruct *test() {
  static MyStruct inst = {0,0};
  if (!inst.clientdata) {
    inst.len = 10;
    inst.clientdata = malloc(sizeof(double)*inst.len);
    for (size_t i = 0; i < inst.len; ++i) {
      inst.clientdata[i] = i;
    }
  }
  return &inst;
}

并运行以下 Python:

import test

for i in test.test():
  print i

哪个打印:

python run.py
0.0
1.0
2.0
3.0
4.0
5.0
6.0
7.0
8.0
9.0

然后完成。


另一种方法,使用类型映射来映射MyStruct onto a 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"

这将创建一个PyList与任何返回 a 的函数的返回值MyStruct *。我测试了这个%typemap(out)与之前的方法具有完全相同的功能。

也可以写一个对应的%typemap(in) and %typemap(freearg)相反,类似这样未经测试的代码:

%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);
}

使用迭代器对于像链表这样的容器来说更有意义,但为了完整性起见,您可能会这样做MyStruct with __iter__。关键是你让 SWIG 为你包装另一种类型,它提供了__iter__() and 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;
  }
}

要求容器迭代 http://docs.python.org/library/stdtypes.html#iterator-types是这样的容器需要实现__iter__()并返回一个新的迭代器,但除了next()它返回下一个项目并递增迭代器,迭代器本身还必须提供__iter__()方法。这意味着容器或迭代器可以相同地使用。

MyStructIter需要跟踪迭代的当前状态——我们在哪里以及还剩下多少。在这个例子中,我通过保留一个指向下一个项目的指针和一个计数器来实现这一点,我们用它来告诉我们何时到达末尾。您还可以通过保留指向的指针来跟踪状态MyStruct迭代器正在使用一个计数器来表示其中的位置,例如:

%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;
  }
}

(在这种情况下,我们实际上可以将容器本身用作迭代器,通过提供__iter__()返回了一个copy容器和一个next()与第一种类似。我在最初的答案中没有这样做,因为我认为这比两种不同的类型更不清楚 - 容器和该容器的迭代器)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

SWIG 将 C 库连接到 Python(从 C“序列”结构创建“可迭代”Python 数据类型) 的相关文章

  • 防止复制构造和返回值引用的分配

    如果我有一个函数返回对类实例的引用 但我无法控制其源 比如说list
  • 将日期(系列)列从一个 DataFrame 添加到其他 Pandas,Python

    我正在尝试将日期列从 df1 广播 到 df2 在 df1 中 我有所有用户的姓名及其基本信息 在 df2 中 我有一个用户购买的列表 df1 和 df2 代码 https i stack imgur com sN0uJ png 假设我有一
  • 捕获当前正在播放的声音

    是否可以捕获计算机上当前播放的声音 如果能够将其保存为 mp3 就好了 但我认为这样做会存在一些法律问题 所以 wav 也可以 我环顾四周 有人建议使用虚拟音频线之类的东西 在 C 中捕获声音输出 https stackoverflow c
  • 抽象类和接口之间的区别[重复]

    这个问题在这里已经有答案了 可能的重复 接口与基类 https stackoverflow com questions 56867 interface vs base class 我不明白抽象类和接口之间的区别 我什么时候需要使用哪种字体
  • 在 C# 中赋值后如何保留有关对象的信息?

    我一直在问我的想法可能是解决方案 https stackoverflow com questions 35254467 is it possible in c sharp to get the attributes attached to
  • 数据框更新后如何刷新绘图?

    假设您已经使用以下方法构建了一个图形px line 使用数据框 数据框稍后会添加新数据 用新数据刷新数据的好方法是什么 一个例子可以是px data stocks 从列的子集开始 GOOG AAPL AMZN FB NFLX MSFT 例如
  • C++ Primer 5th Edition 错误 bool 值没有指定最小大小?

    bool 的最小大小不应该是 1 个字节吗 这有点学术性的东西 尽管它们会转换为数字 并且 与其他所有事物一样 它们最终将基本上由计算机内存中的数字表示 但布尔值不是数字 你的bool可以取值true 或值false 即使您确实需要至少 1
  • 使用 AutoMapper 进行 LINQ GroupBy 聚合

    试图让查询工作 但老实说不确定如何 或者是否可能 进行它 因为我尝试过的一切都不起作用 共查询6个表 Person PersonVote PersonCategory Category City FirstAdminDivision Per
  • 如何在 C++ 中使用 PI 常数

    我想在一些 C 程序中使用 PI 常数和三角函数 我得到三角函数include
  • Chrome 已关闭,并出现错误 ERROR:network_change_notifier_win.cc(141)] WSALookupServiceBegin 失败,原因为:0

    我的笔记本电脑操作系统是 windows 10 我使用 selenium webdriver 和 Python 当我通过脚本打开chrome浏览器时 加载网页后chrome就关闭了 下面是我的python代码和错误 from seleniu
  • 便携式终端

    有没有办法根据所使用的操作系统自动使用正确的 EOL 字符 我在想类似的事情std eol 我知道使用预处理器指令非常容易 但很好奇它是否已经可用 我感兴趣的是 我的应用程序中通常有一些消息 稍后我会将这些消息组合成一个字符串 并且我希望将
  • 为什么我不能在扩展 List 的类中调用 OrderBy?

    我有一堂课 Deck 其中包含一个名为的方法Shuffle 我正在致力于重构Deck延长List
  • 在 MVVM 中,可以在视图后面的代码中访问 ViewModel 吗?

    在 MVVM 模式中 是否可以接受甚至可以访问视图代码后面的 ViewModel 属性 我有一个可观察的集合 它填充在 ViewModel 中 我需要在视图中使用它来绑定到带有链接列表的无限滚动条 IE private LinkedList
  • 删除对象时指针自动指向空

    假设我有一个对象和其他几个不同类类型的对象中的 10 个指向它的指针 如果对象被删除 这些指针必须设置为空 通常我会将对象的类与具有指向它的指针的类互连 以便它可以通知它们它正在被删除 并且它们可以将它们的指针设置为空 但这也有一个负担 即
  • 使用 Python 3.x 基本获取 URL 的 HTML 正文

    我是Python新手 我对 Python 2 x 中的旧 urllib 和 urllib2 与 Python 3 中的新 urllib 之间的差异有点困惑 除此之外 我不确定数据在发送到 urlopen 之前何时需要编码 我一直在尝试使用
  • 加入语音频道(discord.py)

    当我尝试让我的机器人加入我的语音频道时 出现以下错误 await client join voice channel voice channel 产生错误的行 Traceback most recent call last File usr
  • Django 多个外键,相同的相关名称

    我想创建一个模型 1 其中具有相同其他模型 2 的多个外键 我希望这些外键具有相同的related name因为每个外键将指向 model 2 的不同实例 因为我需要所有外键的一个反向关系 也许一个例子会更明确 class Parent M
  • 如何仅更改 DateTime 的日期部分,同时保留时间部分?

    我在代码中使用了很多 DateTime 我想将这些日期时间更改为我的特定日期并保留 时间 1 2012 02 02 06 00 00 gt 2015 12 12 06 00 00 2 2013 02 02 12 00 00 gt 2015
  • ASP.NET Core:会话 ID 始终变化

    今天启动了一个全新的 ASP NET Core 网站 按照说明添加会话 我们在索引页上打印出会话 ID 它始终是唯一的 我认为这可能是 cookie 合规性 所以我在 Chrome 的高级设置和调试器中删除了所有 cookie 但横幅不会再
  • 最后从同一类中的其他构造函数调用构造函数

    我在这里读到可以调用另一个构造函数从同一类中的另一个构造函数调用构造函数 https stackoverflow com questions 829870 calling constructor from other constructor

随机推荐