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

如何让Boost Python实现的数组正常支持Python的for循环?

问题描述

尝试用Boost Python实现自定义数组类,C++代码如下:

#include <boost/python.hpp>
#include <memory>
#include <vector>

class MyObject
{
public:
    MyObject(int value)
        : value_(value)
    {
    }

    int value() const { return value_; }
    void set_value(int value) { value_ = value; }

private:
    int value_;
};

class MyArray
{
public:
    MyArray(int size)
        : array_(size)
    {
        for (auto& obj : array_)
        {
            obj = std::make_shared<MyObject>(0);
        }
    }

    std::shared_ptr<MyObject>& operator[](int index) { return array_[index]; }
    int size() const { return static_cast<int>(array_.size()); }

private:
    std::vector<std::shared_ptr<MyObject>> array_;
};

BOOST_PYTHON_MODULE(example)
{
    namespace python = boost::python;

    python::class_<MyObject, std::shared_ptr<MyObject>>("MyObject", python::init<int>())
        .add_property("value", &MyObject::value, &MyObject::set_value);

    python::class_<MyArray, std::shared_ptr<MyArray>>("MyArray", python::init<int>())
        .def("__getitem__", &MyArray::operator[], boost::python::return_value_policy<boost::python::copy_non_const_reference>())
        .def("__len__", &MyArray::size);
}

数组在Python中基本功能正常:len()能正确返回长度,[]索引访问也正常,但用for循环遍历时无法在正确位置停止,触发C++运行时错误,试图访问不存在的myArray[3]元素。Python测试代码:

my_array = analyse_script.MyArray(3)

my_array[0].value = 1
my_array[1].value = 2
my_array[2].value = 3

print(len(my_array))  # prints "3"

for obj in my_array:
  print(obj.value)  # prints "1", "2", "3"

需要修改哪些部分才能让该数组正常支持Python的for循环?

解决方案

Python的for循环依赖迭代器协议,或者要求__getitem__方法在索引超出范围时抛出**IndexError**异常。当前你的operator[]在C++里越界访问会直接触发运行时错误,而非抛出Python可识别的异常,所以Python无法判断何时停止迭代。

需要做以下修改:

1. 为MyArray::operator[]添加越界检查并抛出Python异常

修改C++代码中的operator[]方法,当索引越界时抛出Python的IndexError:

std::shared_ptr<MyObject>& operator[](int index) {
    if (index < 0 || index >= static_cast<int>(array_.size())) {
        PyErr_SetString(PyExc_IndexError, "Index out of bounds");
        boost::python::throw_error_already_set();
    }
    return array_[index];
}

这样当Python迭代到超出数组长度的索引时,会捕获到IndexError,自动停止循环,不会触发C++运行时错误。

2. (可选)实现迭代器协议(进阶方案)

如果想更规范地支持Python迭代模式,可以为MyArray实现__iter__方法,返回一个迭代器对象。不过对于简单序列类型,仅通过__getitem__抛出IndexError就足以满足for循环的需求。

修改后的完整C++代码如下:

#include <boost/python.hpp>
#include <memory>
#include <vector>

class MyObject
{
public:
    MyObject(int value)
        : value_(value)
    {
    }

    int value() const { return value_; }
    void set_value(int value) { value_ = value; }

private:
    int value_;
};

class MyArray
{
public:
    MyArray(int size)
        : array_(size)
    {
        for (auto& obj : array_)
        {
            obj = std::make_shared<MyObject>(0);
        }
    }

    std::shared_ptr<MyObject>& operator[](int index) {
        if (index < 0 || index >= static_cast<int>(array_.size())) {
            PyErr_SetString(PyExc_IndexError, "Index out of bounds");
            boost::python::throw_error_already_set();
        }
        return array_[index];
    }

    int size() const { return static_cast<int>(array_.size()); }

private:
    std::vector<std::shared_ptr<MyObject>> array_;
};

BOOST_PYTHON_MODULE(example)
{
    namespace python = boost::python;

    python::class_<MyObject, std::shared_ptr<MyObject>>("MyObject", python::init<int>())
        .add_property("value", &MyObject::value, &MyObject::set_value);

    python::class_<MyArray, std::shared_ptr<MyArray>>("MyArray", python::init<int>())
        .def("__getitem__", &MyArray::operator[], boost::python::return_value_policy<boost::python::copy_non_const_reference>())
        .def("__len__", &MyArray::size);
}

内容的提问来源于stack exchange,提问作者BadJerry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 19:07:05