10

我有一个 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);
}

在我试图找出发生了什么的过程中,我放了一堆打印语句。其中之一在段错误之前打印类型名称和引用计数。这导致“函数 3”,所以我必须假设该函数尚未被破坏。

I'm passing the following to swig:

void AddOption (std::string name, PyObject *pycallback);

In which I construct a PyMenuCallback

I'm at a loss for what's causing the segfault, any ideas?

4

1 回答 1

4

Since the C++ calling the python callback is within a wxWidget, and the swig wrapper is generated by the special wxPython swig (wxswig?) There is some thread protection required around the function call...

The fixed operator should look like this

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

Make sure to include

#include "wx/wxPython/wxPython.h"
#include "wx/wxPython/wxPython_int.h"
于 2015-02-18T16:03:41.503 回答