2012-11-23 5 views
5

C 애플리케이션에서 이벤트 기반 파이썬 라이브러리를 사용하고 싶습니다.C로 파이썬 포함하기

C에서 메소드를 호출하고 리턴 값을 수집하는 데 아무런 문제가 없습니다. 그러나 다음 작업을 수행하는 방법을 모르겠습니다.

파이썬 라이브러리 함수 중 일부는 인수로 파이썬 함수 포인터라고 생각합니다.

C에서이 메서드를 호출 할 때 파이썬 함수가 콜백 함수로 C 함수를 사용하도록 C 함수 포인터를 전달할 수 있습니까?

그렇지 않다면 파이썬에서 C 콜백을 사용하는 방법은 무엇입니까?

+0

http://stackoverflow.com/questions/6626167/build-a-pyobject-from-a-c-function (병합해야 함, 모듈 포인트 외)을 참조하십시오. – ecatmur

+1

@ecatmur 연결된 대답이 잘못되었습니다. 'methd'는'PyCFunction'이 제공된'PyMethodDef'에 대한 포인터를 보유하고 나중에 C 함수와 플래그를 검색하기 위해 정적으로 할당되어야합니다. 답안의 코드는'PyMethodDef'를 자동으로 할당합니다. 결과 Python 함수가 호출 될 때 충돌이 발생할 것입니다. – user4815162342

+0

@ user4815162342 : 링크드 인 답변에서 Manux는 프로세스의 개요를 보여준 것 같습니다. 조금 어리석은 IMO입니다. Manux는 함수 이름을'NULL' 대신 모듈 이름으로 사용합니다. 실제 코드에서는'PyMethodDef'가 힙에 할당되었다고 가정합니다. – eryksun

답변

9

이것은 예상했던 것보다 어렵지만 수행 할 수 있습니다. 당신이 선택하려는 경우

#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 기능이있는 경우

, 당신은 호출 파이썬로 변환 PyCFunction_New을 사용할 수 있습니다 런타임에 다른 콜백, 예. C 콜백 함수를 파이썬 콜백으로 변환하는 일반 c_to_python 함수를 제공합니다. 이 경우 자체 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; 
} 

이 코드는 하찮게도 user_data 포인터를 허용하도록 연장된다 사용자 데이터를 CallbackObject 구조체에 저장하면됩니다.

+0

빠른 모양을 보으면 boost :: python이 C 함수를 래핑하는 것처럼 보입니다. – neodelphi

+0

@neodelphi 그것은 이해하지만, 질문에는 C 태그가 붙어있어서'boost :: python'은 실제로 적용되지 않습니다. BTW는'boost :: python'을 적극적으로 유지하고 있습니까? 내가 그것을 점검했을 때 문서는 꽤 오래된 것처럼 보였다. – user4815162342

+0

당신 말이 맞아요. 수년이 지나도 업데이트되지 않았기 때문에 라이브러리와 같은 boost :: python을 구현하려고하기 때문에이 게시물을 발견했습니다. 나는 다른 해결책을 찾지 못했고 boost : : python이 이렇게하는 것을 보았는데, 이것은 할 수있는 방법 인 것 같다. – neodelphi

관련 문제