2012-11-23 35 views
5

Tôi muốn sử dụng thư viện Python dựa trên sự kiện trong ứng dụng C. Tôi sử dụng C-API chính thức để nhúng Python: http://docs.python.org/2/c-api/index.html#c-api-indexNhúng Python bằng C

Không có vấn đề gì khi gọi phương thức từ C và thu thập các giá trị trả lại. Tuy nhiên, tôi không biết cách thực hiện như sau:

Một số chức năng thư viện python lấy những gì tôi nghĩ là con trỏ hàm python làm đối số.

Có thể, khi gọi các phương thức này từ C, để vượt qua con trỏ hàm C để hàm Python sử dụng hàm C làm gọi lại?

Nếu không, làm cách nào để hoàn thành việc sử dụng Python khi gọi lại C?

+0

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

+1

@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

+0

@ 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

Trả lời

9

Đ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.

+0

Có giao diện nhanh, có vẻ như tăng cường :: python thực hiện thao tác này để bao bọc các hàm C. – neodelphi

+0

@neodelphi Nó có nghĩa là nó có, nhưng câu hỏi đã được gắn thẻ C, do đó, 'tăng :: python' không thực sự áp dụng. BTW là 'tăng :: python' tích cực duy trì? Các tài liệu có vẻ khá cũ khi tôi kiểm tra nó. – user4815162342

+0

Bạn nói đúng. Chỉ cần tìm thấy bài đăng này bởi vì tôi đang cố gắng để thực hiện một tăng :: python như thư viện bởi vì nó đã không được cập nhật từ nhiều năm. Tôi đã không tìm thấy bất kỳ giải pháp khác và như tôi thấy tăng :: python hiện theo cách này, điều này có vẻ là cách để làm. – neodelphi