Странное поведение при вызове функций python из cython c

У меня есть код C++, код Python и код Cython. В C++ у меня есть асинхронный обратный вызов, который выполняется, и я хочу, чтобы код Python выполнялся.

Вот что я сделал. На питоне я написал функцию, которая принимала 2 параметра:

def fn(x,y):
    print("hello")
    print(x)
    print(y)

Затем в C++ я хотел вызвать эту функцию "fn" асинхронно в качестве обратного вызова. Поэтому я создал функцию C++ под названием «PythonCallback», чтобы обернуть обратный вызов.

class PythonCallback{
public:
    PyObject *_pyfunc;

    PythonCallback(PyObject *pyfunc);
    void presentCallback(_bstr_t EventName, BYTE* CallbackData);
    void addCallbackToGUID( PyObject* Py_GUID );
}


//Constructor
PythonCallback::PythonCallback(PyObject *pyfunc){
if( PyCallable_Check(pyfunc)){
    Py_INCREF(pyfunc);
    _pyfunc = pyfunc;
}else{
    throw -1;
}
};

void PythonCallback::presentCallback(_bstr_t EventName, BYTE* pCallbackData)
{
PyGILState_STATE gstate;
gstate = PyGILState_Ensure();
EventData* evData = (EventData*)pCallbackData;
PyObject *args = Py_BuildValue("(ss)", EventName, EventName);
const wchar_t* wstring(EventName);
PyObject_CallObject(_pyfunc, args );

std::wstring w;
w.append(EventName);
//    PyObject_CallFunction( _pyfunc, "(ss)", wstring, wstring);
//    PyObject_CallFunction( _pyfunc, "(ss)", w.c_str(),w.c_str());
//    PyObject_CallFunction( _pyfunc, "(s)", w.c_str() );
//    PyObject_CallFunction( _pyfunc, "" );
//    PyObject_CallFunction( _pyfunc, "ss", wstring, wstring );

PyGILState_Release(gstate);

};

И все это склеено с помощью Cython. В Cython я создал класс, который будет отправлять функцию python на C++.

cdef class CallbackInformation:
    cdef PythonCallback *thisptr
    def __cinit__(self, object func):
        self.thisptr = new PythonCallback(func)
        # temp = PythonCallback(func)

    def __dealloc__(self):
        del self.thisptr

    def addCallbackToGUID(self,guid):
        self.thisptr.addCallbackToGUID(guid)

Итак, что бы я сделал, это создать новый экземпляр CallbackInformation и передать ему fn. то есть instance = CallbackInformation(fn)

Проблема возникает, когда я вызываю функцию обратного вызова python fn. Я не получаю немедленную ошибку, но когда я пытаюсь просто проверить fn в консоли Python, т.е. если я просто наберу fn в консоли, я получаю следующую ошибку:

Файл «C:/Users/eric/PycharmProjects/SuperResolution/Startup3dCalibration.py»,> строка 62, в fn print («привет») UnicodeDecodeError: кодек «utf-8» не может декодировать байт 0xf8 в позиции 0: недопустимо> стартовый байт

если я сделаю это снова, я получу его сообщение

привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет, привет.

и, наконец, если я сделаю это в третий раз, я получу ожидаемый результат: <function fn at 0x0000000002281048>

Где я неправ?


person thejinx0r    schedule 26.03.2015    source источник


Ответы (1)


И снова решение приходит сразу после того, как вы публикуете вопрос:

поэтому я понял, что с Py_BuildValue есть фундаментальная разница между строкой char * и строкой Unicode. Итак, простая замена PyObject *args = Py_BuildValue("(ss)", EventName, EventName); на PyObject *args = Py_BuildValue("(uu)", EventName, EventName); решила мою проблему.

Я предполагаю, что ошибка о неконвертируемом юникоде имеет смысл в конце концов.

person thejinx0r    schedule 26.03.2015