Boost.Python使用类型别名触发RecursionError问题求助
问题分析与解决方案
问题根源
- 重复绑定同一包装类到多个Python类型:你用
CppDerivedWrap同时注册了CppDerived和CppDerivedCopy两个Python类,但Boost.Python的class_机制会将包装类与Python类型强关联,重复绑定会导致内部类型解析逻辑混乱,触发无限递归。 - 错误绑定函数到原类而非包装类:暴露
myOverridableCallback时,你绑定了&CppDerived::myOverridableCallback,但CppDerived并未重写该函数,实际调用的是基类CppBase的实现,这直接破坏了Boost.Python的override回调检测逻辑,加剧了递归问题。
修复方案
方案1:复用同一C++类型的注册(推荐)
由于CppDerivedCopy是CppDerived的类型别名,本质是同一个C++类型,无需重复编写包装类或注册逻辑,只需在模块中将已注册的CppDerived赋值给CppDerivedCopy即可:
修改BOOST_PYTHON_MODULE部分代码:
BOOST_PYTHON_MODULE(InheritedFunctionTest) { // 暴露CppBase类 boost::python::class_<CppBaseWrap, boost::noncopyable>("CppBase", boost::python::init<>()) .def("myOverridableCallback", &CppBaseWrap::myOverridableCallback) .def("display", &CppBase::display); // 暴露CppDerived类,绑定包装类的回调函数 auto derived_class = boost::python::class_<CppDerivedWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerived", boost::python::init<>()) .def("myOverridableCallback", &CppDerivedWrap::myOverridableCallback) .def("show", &CppDerived::show); // 将CppDerived赋值给CppDerivedCopy,实现别名效果 boost::python::scope().attr("CppDerivedCopy") = derived_class; }
方案2:为别名创建独立包装(冗余,不推荐)
如果确实需要为别名创建独立的包装结构(无实际必要,因为类型别名指向同一C++类型),可以复制包装类代码并单独注册:
// 为CppDerivedCopy创建独立包装类 struct CppDerivedCopyWrap : public CppDerivedCopy, boost::python::wrapper<CppDerivedCopy> { virtual std::string myOverridableCallback() override { if (boost::python::override f = this->get_override("myOverridableCallback")) { return f(); } return CppBase::myOverridableCallback(); } }; BOOST_PYTHON_MODULE(InheritedFunctionTest) { // ... 保留CppBase的暴露代码 ... // 暴露CppDerived boost::python::class_<CppDerivedWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerived", boost::python::init<>()) .def("myOverridableCallback", &CppDerivedWrap::myOverridableCallback) .def("show", &CppDerived::show); // 暴露CppDerivedCopy,使用独立包装类 boost::python::class_<CppDerivedCopyWrap, boost::python::bases<CppBase>, boost::noncopyable>("CppDerivedCopy", boost::python::init<>()) .def("myOverridableCallback", &CppDerivedCopyWrap::myOverridableCallback) .def("show", &CppDerivedCopy::show); }
关键修正说明
- 必须将
myOverridableCallback绑定到包装类的实现(&CppDerivedWrap::myOverridableCallback),而非原类的函数,这样才能触发Boost.Python的Python override检测逻辑。 - 类型别名无需重复注册新的
class_,直接复用已注册的类对象即可实现Python中别名的效果,避免内部类型冲突。
测试验证
修改后的代码编译后,运行测试脚本:
import sys sys.path.append('./build') import InheritedFunctionTest derived_obj = InheritedFunctionTest.CppDerived() derived_obj.show() # 输出: # CppDerived class show function # Callback triggered from CppBase derived_obj2 = InheritedFunctionTest.CppDerivedCopy() derived_obj2.show() # 输出与上面完全一致
同时,Python中重写myOverridableCallback的逻辑也能正常工作:
class PyDerived(InheritedFunctionTest.CppDerived): def myOverridableCallback(self): return "Callback from Python" py_obj = PyDerived() py_obj.show() # 输出: # CppDerived class show function # Callback from Python
内容的提问来源于stack exchange,提问作者Flabala
相关产品推荐
相关产品推荐

