Dies ist schwieriger als man erwarten würde, aber es kann getan werden.
Wenn Sie eine einzelne C-Funktion, die Sie als Rückruf zur Verfügung stellen möchten, können Sie PyCFunction_New
verwenden Sie es in einen Python zu konvertieren aufrufbar:
#include <python.h>
static PyObject *my_callback(PyObject *ignore, PyObject *args)
{
/* ... */
}
static struct PyMethodDef callback_descr = {
"function_name",
(PyCFunction) my_callback,
METH_VARARGS, /* or METH_O, METH_NOARGS, etc. */
NULL
};
static PyObject *py_callback;
...
py_callback = PyCFunction_New(&callback_descr, NULL);
Dieser Ansatz wird nicht funktionieren, wenn Sie wählen möchten verschiedene Rückrufe zur Laufzeit, z um eine generische c_to_python
-Funktion bereitzustellen, die eine C-Callback-Funktion in einen Python-Callback konvertiert. In diesem Fall müssen Sie einen Erweiterungstyp mit einer eigenen tp_call
implementieren.
typedef struct {
PyObject_HEAD
static PyObject (*callback)(PyObject *, PyObject *);
} CallbackObject;
static PyObject *
callback_call(CallbackObject *self, PyObject *args, PyObject *kwds)
{
return self->callback(args, kwds);
}
static PyTypeObject CallbackType = {
PyObject_HEAD_INIT(NULL)
0, /*ob_size*/
"Callback", /*tp_name*/
sizeof(CallbackObject), /*tp_basicsize*/
0, /*tp_itemsize*/
0, /*tp_dealloc*/
0, /*tp_print*/
0, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash */
(ternaryfunc) callback_call, /*tp_call*/
0, /*tp_str*/
0, /*tp_getattro*/
0, /*tp_setattro*/
0, /*tp_as_buffer*/
Py_TPFLAGS_DEFAULT, /*tp_flags*/
};
PyObject *
c_to_python(PyObject (*callback)(PyObject *, PyObject *))
{
CallbackObject *pycallback = PyObject_New(CallbackObject, &CallbackType);
if (pycallback)
pycallback->callback = callback;
return pycallback;
}
Dieser Code wird für die auch zu akzeptieren, einen Zeiger user_data
trivially verlängert; Speichern Sie einfach die Benutzerdaten in der Struktur CallbackObject
.
Siehe http://stackoverflow.com/questions/6626167/build-a-pyobject-from-a-c-function (muss zusammengeführt werden; out of mod points). – ecatmur
@ecatmur Die verknüpfte Antwort ist falsch. 'methd' muss statisch zugewiesen werden, da' PyCFunction' einen Zeiger auf das angegebene 'PyMethodDef' behält und es später zum Abrufen der C-Funktion und Flags verwendet. Der Code in der Antwort weist das 'PyMethodDef' automatisch zu, was zu einem Absturz führt, wenn die resultierende Python-Funktion aufgerufen wird. – user4815162342
@ user4815162342: In der verknüpften Antwort, ich denke, Manux zeigte nur einen Überblick über den Prozess. Es ist ein bisschen albern, IMO, dass Manux den Funktionsnamen als Modulnamen anstatt nur "NULL" verwendet. Im tatsächlichen Code gehe ich davon aus, dass der 'PyMethodDef' auf dem Heap zugewiesen wurde. – eryksun