You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Boost.Python使用类型别名触发RecursionError问题求助

问题分析与解决方案

问题根源

  1. 重复绑定同一包装类到多个Python类型:你用CppDerivedWrap同时注册了CppDerived和CppDerivedCopy两个Python类,但Boost.Python的class_机制会将包装类与Python类型强关联,重复绑定会导致内部类型解析逻辑混乱,触发无限递归。
  2. 错误绑定函数到原类而非包装类:暴露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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 14:55:59