Điều này khó hơn mong đợi, nhưng có thể thực hiện được.
Nếu bạn có một hàm C duy nhất mà bạn muốn cung cấp như một gọi lại, bạn có thể sử dụng PyCFunction_New
để chuyển đổi nó thành một Python callable:
#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);
Cách tiếp cận này sẽ không hoạt động nếu bạn muốn chọn callbacks khác nhau tại thời gian chạy, ví dụ để cung cấp chức năng chung của c_to_python
chuyển đổi chức năng gọi lại C thành một cuộc gọi lại bằng Python. Trong trường hợp đó, bạn sẽ cần phải triển khai loại tiện ích mở rộng với số riêng là tp_call
.
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;
}
Mã này được mở rộng tầm thường để cũng chấp nhận con trỏ user_data
; chỉ lưu trữ dữ liệu người dùng trong cấu trúc CallbackObject
.
Xem http://stackoverflow.com/questions/6626167/build-a-pyobject-from-a-c-function (cần được hợp nhất; ngoài các điểm mod). – ecatmur
@ecatmur Câu trả lời được liên kết là không đúng. 'methd' phải được phân bổ tĩnh bởi vì' PyCFunction' giữ một con trỏ tới 'PyMethodDef' được cung cấp và sử dụng nó sau này để lấy hàm C và cờ. Mã trong câu trả lời tự động phân bổ 'PyMethodDef', điều này sẽ gây ra sự cố khi hàm Python kết quả được gọi. – user4815162342
@ user4815162342: Trong câu trả lời được liên kết, tôi nghĩ Manux chỉ hiển thị tổng quan về quy trình. Đó là một chút ngớ ngẩn, IMO, rằng Manux sử dụng tên hàm như tên mô-đun thay vì chỉ 'NULL'. Trong mã thực tế tôi giả sử 'PyMethodDef' được cấp phát trên heap. – eryksun