我遇到了一些问题,希望获得帮助。我有一个片段代码,用于嵌入python脚本。这个python脚本包含一个函数,该函数将期望接收一个数组作为参数(在这种情况下,我正在python脚本内使用numpy数组)。我想知道如何将数组从C传递到嵌入式python脚本,作为脚本内函数的参数。更具体地说,有人可以告诉我一个简单的例子。
确实,最好的答案可能是仅使用numpy
数组,即使是从C代码中也是如此。但是,如果那不可能,那么您将遇到与在C类型和Python类型之间共享数据的任何代码相同的问题。
通常,在C和Python之间共享数据至少有五个选项:
list
或其他要传递的对象。__getitem__
等)。intptr_t
,或显式ctypes
类型,或者不进行铸造;然后ctypes
在Python端使用进行访问。const char *
并将其作为传递str
(或在Py3中为bytes
),并在Python端使用struct
或ctypes
访问它。buffer
协议匹配的对象,然后在Python端再次使用struct
或ctypes
。在您的情况下,您想numpy.array
在Python中使用。因此,一般情况变为:
numpy.array
通行证。ctypes
的类型numpy
。const char *
并将其作为str
(或在Py3中为bytes
)传递,该类型已经numpy
可以转换为数组。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
等效项(假设您可以依靠Carray
而不被删除-
请参阅文档中的创建数组,以获取有关您的选项的更多详细信息,在这里):
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
和抽象类型(例如)的APIPyMapping
非常简单,即使将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;
}
如果您使用的是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并不是那么容易上手,但是一旦完成所有事情,几乎所有的事情都以您期望的方式完成,并且可以正常工作,对于嵌入和扩展来说也是如此。等等。
问题内容: 我有一个bash脚本a.sh,其中有一个python脚本b.py。python脚本计算某些内容,我希望它返回一个值,该值稍后将在a.sh中使用。我知道我能做 在a.sh中: 在b.py中: 但这不是那么方便,因为我还在b.py中打印了其他消息 有什么更好的方法吗? 编辑: 我现在正在做的只是 这意味着我可以在b.py中打印很多东西,但是只有最后一行(假设它不包含“ \ n”,这是最后一
问题内容: 我在C 中有一个方法,该方法将双精度数组作为参数。我从Java调用此方法,需要传递一个双精度数组。C 例程读取和修改数组的值,而我需要Java中的那些更新后的值。我该怎么做呢? 例如,使用C ++例程: 和Java代码: 我猜不能像上面的调用那样对myMethod进行调用…还是可以吗?而在Swig中进行这项工作所需的是什么。如果我无法进行上述调用,如何将我的值获取到C ++代码? 问题
我在java程序中嵌入了fop: 现在我的xsl (main_structure.xsl)需要一个参数来运行 在控制台中,我将使用“-param name value”属性将该参数传递给fop。 那么,在fop的嵌入式版本中,如何将一个参数传递到我的xsl文件中呢?
问题内容: 我正在学习如何在Python中嵌入Rust函数,并且如果我的输入是s而不是list ,一切都可以正常工作。 如果我的文件是: 我可以这样使用: 但是,如果我更改为: 我不能再在Python中使用它(此编译良好): 原因,尽管我可以这样做是因为Python和Rust都是 动态数组 ,但显然我在这里缺少了一些东西。 为什么我的尝试不起作用?我该怎么做才能解决? 问题答案: 不要这样做: 基
我试图在php脚本和c程序之间传递参数。我的php脚本如下所示 然后我想我的c程序返回给我一个字符串(但我真的不知道怎么做),你能帮忙吗?
这里是HTML文件,在脚本部分,我发出了一个ajax请求,将一些字符串传递给python函数。 在中,我设置了python脚本的路径。Python文件,我希望在该文件中从JS获取所请求的数据并将其打印出来。 注意:这里我没有使用任何框架。只是纯HTML、JS和Python文件。