从 cython c 调用 python 函数时的奇怪行为

Posted

技术标签:

【中文标题】从 cython c 调用 python 函数时的奇怪行为【英文标题】:Strange behaviour when calling python functions from cython c 【发布时间】:2015-03-26 14:20:17 【问题描述】:

我有一些 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 中,我创建了一个将 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,我会收到以下错误:

文件“C:/Users/eric/PycharmProjects/SuperResolution/Startup3dCalibration.py”,>第 62 行,在 fn 打印(“你好”) UnicodeDecodeError:“utf-8”编解码器无法解码位置 0 的字节 0xf8:无效>开始字节

如果我再做一次, 我收到了他的消息

hellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohellohello

最后,如果我第三次这样做,我会得到预期的输出: <function fn at 0x0000000002281048>

我哪里做错了?

【问题讨论】:

【参考方案1】:

再一次,解决方案在您发布问题后立即出现:

所以我意识到使用Py_BuildValuechar * 字符串和 unicode 字符串之间存在根本区别。因此,只需将 PyObject *args = Py_BuildValue("(ss)", EventName, EventName); 替换为 PyObject *args = Py_BuildValue("(uu)", EventName, EventName); 即可解决我的问题。

我猜想关于 unconvertable unicode 的错误最终是有道理的。

【讨论】:

以上是关于从 cython c 调用 python 函数时的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章

包装采用 char** [in/out] 的 C 函数调用,以在 cython 中返回 python 列表

『Python CoolBook』Cython

如何在 Cython 中调用多线程 C 函数?

cython与python的不同都有哪些

如何将 Cython 生成的模块从 python 导入 C/C++ 主文件? (用 C/C++ 编程)[关闭]

cython和python的区别