从 cython c 调用 python 函数时的奇怪行为
Strange behaviour when calling python functions from cython c
我有一些 C++ 代码,一些 python 代码和一些 cython 代码。
在 C++ 中,我有一个被执行的异步回调,我希望执行 python 代码。
这是我所做的。
在 python 中,我写了一个带有 2 个参数的函数:
def fn(x,y):
print("hello")
print(x)
print(y)
然后,在 C++ 中,我想异步调用此函数 "fn" 作为回调。
所以我创建了一个名为 "PythonCallback" 的 C++ 函数来包装回调。
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 中,我创建了一个 class,它将 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
时出现问题。
我没有立即收到错误,但是当我尝试在 python 控制台中检查 fn
时,即如果我在控制台中键入 fn,我会收到以下错误:
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
如果我再做一次,
我收到他的消息
hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello
最后,如果我第三次这样做,我会得到预期的输出:
<function fn at 0x0000000002281048>
我哪里错了?
再一次,解决方案紧随 post 问题:
所以我意识到使用 Py_BuildValue
,char *
字符串和 unicode 字符串之间存在根本区别。因此,只需将 PyObject *args = Py_BuildValue("(ss)", EventName, EventName);
替换为 PyObject *args = Py_BuildValue("(uu)", EventName, EventName);
即可解决我的问题。
我想关于不可转换的 unicode 的错误最终是有道理的。
我有一些 C++ 代码,一些 python 代码和一些 cython 代码。 在 C++ 中,我有一个被执行的异步回调,我希望执行 python 代码。
这是我所做的。 在 python 中,我写了一个带有 2 个参数的函数:
def fn(x,y):
print("hello")
print(x)
print(y)
然后,在 C++ 中,我想异步调用此函数 "fn" 作为回调。 所以我创建了一个名为 "PythonCallback" 的 C++ 函数来包装回调。
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 中,我创建了一个 class,它将 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
时出现问题。
我没有立即收到错误,但是当我尝试在 python 控制台中检查 fn
时,即如果我在控制台中键入 fn,我会收到以下错误:
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
如果我再做一次, 我收到他的消息
hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello
最后,如果我第三次这样做,我会得到预期的输出:
<function fn at 0x0000000002281048>
我哪里错了?
再一次,解决方案紧随 post 问题:
所以我意识到使用 Py_BuildValue
,char *
字符串和 unicode 字符串之间存在根本区别。因此,只需将 PyObject *args = Py_BuildValue("(ss)", EventName, EventName);
替换为 PyObject *args = Py_BuildValue("(uu)", EventName, EventName);
即可解决我的问题。
我想关于不可转换的 unicode 的错误最终是有道理的。