简体   繁体   中英

Strange behaviour when calling python functions from cython c

I have some C++ code, some python code and some cython code. In C++, I have an asynchronous callback that gets executed, and I want python code to be executed.

Here's what I did. In python, I wrote a function that took 2 parameters:

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

Then, in C++, I wanted to call this function "fn" asynchronously as a callback. So I created a C++ function called "PythonCallback" to wrap the callback.

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);

};

And all of this is glued together with Cython. In Cython, I created a class that would send the python function to 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)

So, then what I would do is create a new instance of CallbackInformation and pass it the fn . ie instance = CallbackInformation(fn)

The problem happens when I call the python callback function fn . I don't get an immediate error, but when I try to just check fn in the python console, ie if I just type fn in the console, I get the following error:

File "C:/Users/eric/PycharmProjects/SuperResolution/Startup3dCalibration.py", >line 62, in fn print("hello") UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf8 in position 0: invalid >start byte

if I do it again, I get his message

hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello

and finally, if I do it a third time, I get the expected output: <function fn at 0x0000000002281048>

Where did I go wrong?

Yet again, the solution comes right after you post the question:

so I realized that with Py_BuildValue , there's a fundamental difference between a char * string and a unicode string. So, simply replacing PyObject *args = Py_BuildValue("(ss)", EventName, EventName); with PyObject *args = Py_BuildValue("(uu)", EventName, EventName); fixed my problem.

I guess the error about unconvertable unicode makes sense in the end.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM