use*_*948 10 python embedding python-c-api
我遇到了一些问题,希望得到一些帮助.我有一个片段代码,用于嵌入python脚本.这个python脚本包含一个函数,它希望接收一个数组作为参数(在这种情况下,我在python脚本中使用numpy数组).我想知道如何将数组从C传递给嵌入式python脚本作为脚本中函数的参数.更具体地说,有人可以向我展示一个简单的例子.
aba*_*ert 18
真的,这里最好的答案可能就是使用numpy数组,即使是从你的C代码.但是,如果这不可能,那么您遇到的问题与在C类型和Python类型之间共享数据的任何代码相同.
通常,在C和Python之间共享数据至少有五个选项:
list要传递的Python 或其他对象.__getitem__等等).intptr_t为显式ctypes类型,或者只是将其保持为un-cast; 然后ctypes在Python端使用它来访问它.const char *并将其作为str(或在Py3中bytes)传递,并使用struct或ctypes在Python端访问它.buffer协议匹配的对象,并再次使用struct或ctypes在Python端.在您的情况下,您希望numpy.array在Python中使用s.因此,一般情况变为:
numpy.array传递.ctypes将其numpy转换为可转换为数组的类型.const char *并将其作为str(或在Py3中bytes)传递,这已经是numpy可以转换为数组的类型.buffer协议的对象,我相信我numpy可以直接转换.对于1,这里是如何使用a 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;
}
Run Code Online (Sandbox Code Playgroud)
这是numpy.array等效的(假设您可以依赖C array不被删除 - 请参阅在文档中创建数组,以获取有关您的选项的更多详细信息):
PyObject *makearray(int array[], size_t size) {
npy_int dim = size;
return PyArray_SimpleNewFromData(1, &dim, (void *)array);
}
Run Code Online (Sandbox Code Playgroud)
无论如何,无论如何,你最终会得到一些看起来像是PyObject *来自C(并且有一个引用计数)的东西,所以你可以将它作为函数参数传递,而在Python端它看起来像numpy.array,list,bytes或其他任何合适的东西.
现在,你如何实际传递函数参数?好吧,您在评论中引用的Pure Embedding中的示例代码显示了如何执行此操作,但并未真正解释正在发生的事情.实际上,扩展文档中的解释比嵌入文档更多,特别是从C调用Python函数.另外,请记住,标准库源代码充满了这样的示例(尽管其中一些不是可读的,或者是因为优化,或者仅仅是因为它们尚未更新以利用新的简化C API特性).
跳过关于从Python获取Python函数的第一个例子,因为大概你已经有了.第二个例子(以及关于它的段落)显示了这样做的简单方法:使用创建参数元组Py_BuildValue.所以,假设我们想要调用一个你已经存储的函数和上面那个函数返回myfunc的列表.这是你做的:mylistmakelist
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;
Run Code Online (Sandbox Code Playgroud)
当然,如果你确定你有一个有效的可调用对象,你可以跳过可调用的检查.(通常情况下,最好先检查一下myfunc,如果合适的话,因为你可以通过这种方式提供更早和更好的错误反馈.)
如果你想真正理解发生了什么,那就试试吧Py_BuildValue.正如文档所说,第二个参数[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);
Run Code Online (Sandbox Code Playgroud)
但通常,Py_BuildValue更容易(特别是如果你还没有把所有内容打包成Python对象),并且代码中的意图更清晰(就像使用PyArg_ParseTuple比tuple在另一个方向上使用显式函数更简单和清晰).
那么,你怎么做到的myfunc?好吧,如果你已经从嵌入代码创建了函数,只需保持指针.如果你想从Python代码传入它,那正是第一个例子所做的.如果你想,例如,从模块或其他上下文中查找名称,具体类型的API PyModule和类似的抽象类型PyMapping非常简单,并且通常很明显如何将Python代码转换为等效的C代码,即使结果大多是丑陋的样板.
把它们放在一起,假设我有一个C数组的整数,我想import mymodule调用一个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;
}
Run Code Online (Sandbox Code Playgroud)
如果您正在使用C++,您可能想要查看某种范围内的看门人/看门人/等.处理所有这些Py_DECREF调用,特别是一旦你开始进行适当的错误处理(这通常意味着return NULL通过函数填充的早期调用).如果你正在使用C++ 11或Boost,unique_ptr<PyObject, Py_DecRef>可能就是你所需要的.
但实际上,如果你计划进行大量的C < - > Python通信,那么减少所有丑陋样板的更好方法是查看所有为改进扩展Python- Cython而设计的熟悉框架,boost :: python,即使你正在嵌入,你也可以有效地完成与扩展相同的工作,因此他们可以以同样的方式提供帮助.
就此而言,如果您搜索文档,其中一些还有帮助嵌入部分的工具.例如,您可以使用C代码和Python代码在Cython中编写主程序cython --embed.您可能想要交叉手指和/或牺牲一些鸡,但如果它有效,它就会非常简单和富有成效.Boost并不是一件容易上手的事情,但是一旦你把事情放在一起,几乎所有东西都完全按照你期望的方式完成,并且正常工作,这就像嵌入式扩展一样真实.等等.
| 归档时间: |
|
| 查看次数: |
11672 次 |
| 最近记录: |