C++/Boost Python class overriding

C++/Boost Python class overriding

本文关键字:class overriding Python Boost C++      更新时间:2023-10-16

好。我的问题实际上很简单。这是一个框架听众类和Python包装类,然后由Boost Python使用:

class FrameListener
    {
    public:
        struct FrameEvent
        {
            double TimeSinceLastEvent;
            double TimeSinceLastFrame;
        };
        FrameListener() {}
        ~FrameListener() {}
        virtual void FrameStart(FrameEvent& evt) = 0;
        virtual void FrameEnd(FrameEvent& evt) = 0;
        virtual void OnFrame(FrameEvent& evt) = 0;
    };
    class FrameListener_PyWrapper : public FrameListener, public boost::python::wrapper<FrameListener>
    {
    public:
        FrameListener_PyWrapper() {}    
        ~FrameListener_PyWrapper();
        void FrameStart(FrameEvent& evt);
        void FrameEnd(FrameEvent& evt);
        void OnFrame(FrameEvent& evt);
    };

然后将类包装以提升Python:

class_<SL_Engine::FrameListener::FrameEvent>("FrameEvent")
        .def_readonly("TimeSinceLastEvent", &SL_Engine::FrameListener::FrameEvent::TimeSinceLastEvent)
        .def_readonly("TimeSinceLastFrame", &SL_Engine::FrameListener::FrameEvent::TimeSinceLastFrame);
    class_<SL_Engine::FrameListener_PyWrapper, boost::noncopyable>("FrameListener")
        .def("OnFrame", pure_virtual(&SL_Engine::FrameListener::OnFrame))
        .def("FrameStart", pure_virtual(&SL_Engine::FrameListener::FrameStart))
        .def("FrameEnd", pure_virtual(&SL_Engine::FrameListener::FrameEnd))
        ;

这可以在python中覆盖以创建自己的帧侦听器类:

class SimpleListen(FrameListener):
def __init__(self):
    pass
def FrameEndd(self, evt):
    pass

然后,您可以创建新的SimpleListener类的实例,然后使用core_engine.addframelistener()函数将其"注册"到引擎。然后,该函数使用boost :: python :: extract()提取它,然后将其放在sTD :: frame侦听器的向量上,然后将其执行每个帧。这可以很好地工作,但是如果我忘记在简单的类中定义基础或拼写错误,则显然会导致崩溃。我已经在Google上搜索了BOOST :: PYTHON或C/PYTHON API,如何测试是否正确定义了基类。AddFrameListener采用PyObject*参数。我想测试PyObject是否首先是类类型。如果您不小心尝试放置一个整数值或程序将确定对象不是类类型的错误和消息。如果是类型,我想测试它是否具有基类,并且是否可以将其提取到Framelistener_pywrapper*。稍后,我想测试每个单独的函数(FRAMESTART,FRAMEDEND和ONFRAME),如果它们在Python类中占据,并且是否匹配参数。如何从Python函数中获取参数列表?如果Python班级的任何功能都不是过度的,它将给我发出警告。如果参数不匹配,您尝试致电:

if (boost::python::override f = this->get_override("FrameEnd"))
    {
        f(evt);
        return;
    }

它将导致崩溃,而没有任何有关错误的信息。我想在调用AddFrameStener函数时检查参数是否匹配并保存信息,如果任何功能都无法正确覆盖,则引擎不会调用它们。

崩溃可能与您在没有GIL锁定的情况下呼叫到Python的事实有关。您每次与Python对象进行互动时都应锁定它:

    /*
This RAII structure ensures that threads created on the native C side
adhere to the laws of Python and ensure they grab the GIL lock when
calling into python
*/
struct PyLockGIL
{
    PyLockGIL()
        : gstate(PyGILState_Ensure())
    { 
    }
    ~PyLockGIL()
    {
        PyGILState_Release(gstate);
    }
    PyLockGIL(const PyLockGIL&) = delete;
    PyLockGIL& operator=(const PyLockGIL&) = delete;
    PyGILState_STATE gstate;
};

然后在回调python之前使用它:

    if (override fe = this->get_override("FrameEnd"))
{
    PyLockGIL lock;
    try
    {
        fe();
        return;
    }
    catch (const error_already_set&)
    {
        std::cout << "Exception in FrameEnd in application";
        PyErr_Print();
    }
}
else
{
    std::cout << "FrameEnd called but not overridden";
}