栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

如何将数组从C传递到嵌入式python脚本

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

如何将数组从C传递到嵌入式python脚本

确实,最好的答案可能是仅使用

numpy
数组,即使是从C代码中也是如此。但是,如果那不可能,那么您将遇到与在C类型和Python类型之间共享数据的任何代码相同的问题。

通常,在C和Python之间共享数据至少有五个选项:

  1. 创建一个Python
    list
    或其他要传递的对象。
  2. 定义一个新的Python类型(在您的C代码中),以包装和表示数组,并使用与在Python中为序列对象定义的方法相同的方法(
    __getitem__
    等)。
  3. 将指向数组的指针强制转换为
    intptr_t
    ,或显式
    ctypes
    类型,或者不进行铸造;然后
    ctypes
    在Python端使用进行访问。
  4. 将指针强制转换为数组
    const char *
    并将其作为传递
    str
    (或在Py3中为
    bytes
    ),并在Python端使用
    struct
    ctypes
    访问它。
  5. 创建一个与
    buffer
    协议匹配的对象,然后在Python端再次使用
    struct
    ctypes

在您的情况下,您想

numpy.array
在Python中使用。因此,一般情况变为:

  1. 创建
    numpy.array
    通行证。
  2. (可能不合适)
  3. 照原样将指针传递给数组,然后从Python使用将该指针转换为可以转换为数组
    ctypes
    的类型
    numpy
  4. 将指针强制转换为数组,
    const char *
    并将其作为
    str
    (或在Py3中为
    bytes
    )传递,该类型已经
    numpy
    可以转换为数组。
  5. 创建一个与
    buffer
    协议匹配的对象,我相信它
    numpy
    可以直接转换。

对于1,下面是使用的方法

list
,仅因为这是一个非常简单的示例(我已经写过它了……):

PyObject *makelist(int array[], size_t size) {    PyObject *l = PyList_New(size);    for (size_t i = 0; i != size; ++i) {        PyList_SET_ITEM(l, i, PyInt_FromLong(array[i]));    }    return l;}

这就是

numpy.array
等效项(假设您可以依靠C
array
而不被删除-
请参阅文档中的创建数组,以获取有关您的选项的更多详细信息,在这里):

PyObject *makearray(int array[], size_t size) {    npy_int dim = size;    return PyArray_SimpleNewFromData(1, &dim, (void *)array);}

无论如何,无论如何,您最终都会得到看起来像

PyObject*
C中的a(并且具有单个refcount),因此您可以将其作为函数参数进行传递,而在Python方面,它看起来像是a
numpy.array
list
bytes
或其他合适的方法。

现在,您如何实际传递函数参数?好吧,您在注释中引用的Pure
Embedding
中的示例代码显示了如何执行此操作,但并未真正解释正在发生的事情。实际上,与嵌入文档相比,扩展文档中的解释更多,尤其是从C调用Python函数。另外,请记住,标准库的源代码中充斥着许多此类示例(尽管由于优化或仅仅是因为尚未进行更新以利用这些优点,所以其中的一些示例并非如其可读性那样好)新的简化的C
API功能)。

跳过有关从Python获取Python函数的第一个示例,因为大概您已经拥有了它。第二个示例(及其右侧的段落)展示了一种简单的方法:使用创建一个参数元组

Py_BuildValue
。因此,假设我们要调用存储在上面的函数返回
myfunc
的列表
mylist
中的
makelist
函数。这是您的工作:

if (!PyCallable_Check(myfunc)) {    PyErr_SetString(PyExc_TypeError, "function is not callable?!");    return NULL;}PyObject *arglist = Py_BuildValue("(o)", mylist);PyObject *result = PyObject_CallObject(myfunc, arglist);Py_DECREF(arglist);return result;

当然,如果确定具有有效的可调用对象,则可以跳过可调用检查。(

myfunc
如果合适的话,通常最好检查一下什么时候第一次得到,因为这样可以给您更早更好的错误反馈。)

如果您想真正了解发生了什么,请尝试使用

Py_BuildValue
。如文档所述,to的第二个参数
[PyObject_CallObject][6]
是一个元组,并且
PyObject_CallObject(callable_object,args)
等效于
apply(callable_object,args)
,等效于
callable_object(*args)
。因此,如果您想使用
myfunc(mylist)
Python进行调用,则必须将其有效地转换为,
myfunc(*(mylist,))
以便将其转换为C。您可以构建
tuple
如下所示的代码:

PyObject *arglist = PyTuple_Pack(1, mylist);

但是通常,

Py_BuildValue
它更容易(尤其是如果您还没有将所有内容打包为Python对象),并且代码中的意图更加清晰(就像在另一个方向上
PyArg_ParseTuple
使用显式
tuple
函数一样,使用起来也越来越简单)。

那么,你怎么得到的

myfunc
呢?好吧,如果您是从嵌入代码创建函数的,则只需保持指针不变即可。如果您希望它从Python代码传入,那正是第一个示例所做的。例如,如果要从模块或其他上下文中按名称查找,则用于具体类型(例如)
PyModule
和抽象类型(例如)的API
PyMapping
非常简单,即使将Python代码转换为等效的C代码,通常也很明显结果大多是丑陋的样板。

综上所述,假设我有一个C整数数组,我想

importmymodule
调用
mymodule.myfunc(mylist)
返回int的函数。这是一个简化的示例(未经实际测试,没有错误处理,但应显示所有部分):

int callModuleFunc(int array[], size_t size) {    PyObject *mymodule = Pyimport_importModule("mymodule");    PyObject *myfunc = PyObject_GetAttrString(mymodule, "myfunc");    PyObject *mylist = PyList_New(size);    for (size_t i = 0; i != size; ++i) {        PyList_SET_ITEM(l, i, PyInt_FromLong(array[i]));    }    PyObject *arglist = Py_BuildValue("(o)", mylist);    PyObject *result = PyObject_CallObject(myfunc, arglist);    int retval = (int)PyInt_AsLong(result);    Py_DECREF(result);    Py_DECREF(arglist);    Py_DECREF(mylist);    Py_DECREF(myfunc);    Py_DECREF(mymodule);    return retval;}

如果您使用的是C
,则可能需要研究某种范围保护器/管理员/等。来处理所有这些

Py_DECREF
调用,尤其是在您开始进行适当的错误处理后(通常意味着
returnNULL
通过该功能进行早期调用)。如果您使用的是C 11或Boost,则
unique_ptr<PyObject,Py_DecRef>
可能仅需这些。

但是,实际上,如果您打算进行大量C <->
Python通信,那么减少所有这些丑陋模板的更好方法是查看所有旨在改善扩展Python的熟悉框架,包括Cython,boost
::
python,等等。即使您正在嵌入,也可以有效地进行与扩展相同的工作,因此它们可以以相同的方式提供帮助。

为此,如果您在文档中搜索,其中的一些工具
将提供帮助嵌入部分的工具。例如,您可以使用C代码和Python代码以及使用Cython编写主程序

cython--embed
。您可能需要用手指交叉和/或牺牲一些鸡肉,但是如果可以的话,它非常简单且高效。Boost并不是那么容易上手,但是一旦完成所有事情,几乎所有的事情都以您期望的方式完成,并且可以正常工作,对于嵌入和扩展来说也是如此。等等。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/624770.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号