gpt4 book ai didi

python - 嵌入 CPython : how do you constuct Python callables to wrap C callback pointers?

转载 作者:行者123 更新时间:2023-11-28 21:35:36 26 4
gpt4 key购买 nike

假设我将 CPython 解释器嵌入到一个用 C 编写的更大程序中。程序的 C 组件有时需要调用用 Python 编写的函数,将回调函数作为参数提供给它们。

使用 CPython extending and embedding API,我如何构造一个包装 C 函数指针的 Python“可调用”对象,以便我可以将该对象传递给 Python 代码并让 Python 代码成功回调到 C 代码中?

Note: this is a revised version of a question originally posted by user dhanasubbu, which I answered, but which was then deleted. I think it was actually a good question, so I have converted what I wrote into a self-answer to my own statement of the question. Alternative answers are welcome.

最佳答案

在 Python 使用的意义上定义一个“可调用”的扩展类型
术语,您填写 tp_call类型对象的槽,它是 __call__ 的 C 等价物特殊方法。进入该槽的函数将是调用实际 C 回调的粘合例程。这是最简单情况的代码,当 C 回调不接受任何参数并且不返回任何内容时。

typedef struct {
PyObject_HEAD
/* Type-specific fields go here. */
void (*cfun)(void); /* or whatever parameters it actually takes */
} CallbackObj;

static PyObject *Callback_call(PyObject *self, PyObject *args, PyObject *kw)
{
/* check that no arguments were passed */
const char no_kwargs[] = { 0 };
if (!PyArg_ParseTupleAndKeywords(args, kw, "", no_kwargs))
return 0;

CallbackObj *cself = (CallbackObj *)self;
cself->cfun();
Py_RETURN_NONE;
}

static PyTypeObject CallbackType = {
PyVarObject_HEAD_INIT(NULL, 0)
.tp_name = "mymodule.Callback",
.tp_doc = "Callback function passed to foo, bar, and baz.",
.tp_basicsize = sizeof(CallbackObj),
.tp_itemsize = 0,
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_new = PyType_GenericNew,
.tp_call = Callback_call,
};
PyType_Ready 实例化类型对象照常。但是,不要将它放在 Python 可见的任何模块中,因为 Python 代码无法正确创建这种类型的实例。 (正因为如此,我没有使用 tp_init 函数;只要确保在从 C 创建实例后总是初始化 ->cfun,否则 Callback_call 会崩溃。)
现在,假设您需要调用的实际函数名为 real_callback ,并且您想要将其传递给的 Python 函数名为 function_to_call .首先,您创建一个回调对象,通过
像往常一样调用类型对象,并初始化它的 ->cfun field :
    PyObject *args = PyTuple_New(0);
CallbackObj *cb = (CallbackObj *)PyObject_CallObject(
(PyObject *)CallbackType, args);
Py_DECREF(args);
cb->cfun = real_callback;
然后你把 cb进入一个参数元组,并调用 Python 函数
像往常一样反对。
    args = Py_BuildValue("(O)", cb);
PyObject *ret = PyObject_CallObject(function_to_call, args);
Py_DECREF(args);
Py_DECREF(cb);
// do stuff with ret, here, perhaps
Py_DECREF(ret);
将此扩展到更复杂的情况,其中 C 回调需要接受参数和/或返回值和/或在错误时引发 Python 异常和/或从外部上下文接收“关闭”信息,留作练习。

关于python - 嵌入 CPython : how do you constuct Python callables to wrap C callback pointers?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52079835/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com