我有一个wx.py.Shell.shell小部件,它允许用户执行与我的程序交互的python代码。我希望能够将用户在此空间中定义的函数传递给我的C ++代码(通过wxswig生成的自定义小部件包装器)并执行它。
在我的C ++代码中,我正在使用std :: function<>用于调用绑定函数的类(C ++或Python)
所以我创建了一个简单的类来用函数调用操作符包装PyObject。但是当我尝试调用PyObject *时,我得到了段错误。
class PyMenuCallback
{
PyObject *Func;
public:
PyMenuCallback(const PyMenuCallback &op2);
PyMenuCallback(PyObject *func);
~PyMenuCallback ();
void operator() (int id);
};
/////////////////////////////////////////////////////////
PyMenuCallback::PyMenuCallback(PyObject *func)
: Func(func)
{
Py_XINCREF (Func);
if(!PyCallable_Check(Func))
cout << "Not a Callable Callback." << endl; //Throw an exception or something
}
PyMenuCallback::PyMenuCallback(const PyMenuCallback &op2)
: Func (op2.Func)
{
Py_XINCREF (Func);
if(!PyCallable_Check(Func))
cout << "Not a Callable Callback." << endl;
}
PyMenuCallback::~PyMenuCallback()
{
Py_XDECREF (Func);
}
void PyMenuCallback::operator() (int id)
{
cout << "Calling Callback" << endl;
if (Func == 0 || Func == Py_None || !PyCallable_Check(Func))
return;
cout << "Building Args" << endl;
PyObject *arglist = Py_BuildValue ("(i)",id);
cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl;
PyObject *result = PyObject_Call(Func,arglist,0); //<<<<<---SEGFAULTS HERE
cout << "Executed" << endl;
Py_DECREF(arglist);
Py_XDECREF(result);
}
在我试图找到正在发生的事情时,我放了一堆打印语句。 其中一个在segfault之前打印类型名称和引用计数。这导致“功能3”,所以我必须假设该功能尚未被破坏。
我将以下内容传递给swig:
void AddOption (std::string name, PyObject *pycallback);
我在其中构建了一个PyMenuCallback
我对导致段错误的原因感到茫然,还有什么想法?
答案 0 :(得分:4)
由于调用python回调的C ++在wxWidget中,并且swig包装器是由特殊的wxPython swig(wxswig?)生成的。函数调用周围需要一些线程保护...
固定运算符应如下所示
void PyMenuCallback::operator() (int id)
{
cout << "Calling Callback" << endl;
if (Func == 0 || Func == Py_None || !PyCallable_Check(Func))
return;
cout << "Building Args" << endl;
PyObject *arglist = Py_BuildValue ("(i)",id);
cout << "Built: " << arglist << endl;
cout << "Func: " << Func->ob_type->tp_name << " " << Func->ob_refcnt << endl;
wxPyBlock_t blocked = wxPyBeginBlockThreads(); //Anti-WxSwig
PyObject *result = PyObject_Call(Func,arglist,0);
wxPyEndBlockThreads(blocked);
cout << "Executed" << endl;
Py_XDECREF(arglist);
Py_XDECREF(result);
}
确保包含
#include "wx/wxPython/wxPython.h"
#include "wx/wxPython/wxPython_int.h"