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

Swig封装C++容器时__getitem__触发StopIteration致脚本终止求正解

解决方法

你的问题出在SWIG生成的Python包装函数无法正确处理C++层直接设置的PyExc_StopIteration错误,导致脚本异常终止。以下是两种正确的实现方式:

方式一:在Python层处理迭代终止(推荐)

通过拆分底层获取逻辑和Python层的异常抛出逻辑,避免C++层直接操作Python错误状态:

  1. 修改SWIG接口文件,将原__getitem__重命名为底层调用函数,再用%pythoncode实现符合Python规范的__getitem__:
%template(vectorModelDescriptor) com_cae::physiology::vector<::IModelDescriptor*>;

%extend com_cae::physiology::vector<::IModelDescriptor*> {
    // 底层获取元素的函数,仅返回NULL表示越界
    IModelDescriptor* _getitem(unsigned int i) {
        if (i >= self->size()) {
            return NULL;
        }
        return (*self)[i];
    }
}

// 用Python代码重写__getitem__,处理迭代终止逻辑
%pythoncode %{
    def __getitem__(self, i):
        item = self._getitem(i)
        if item is None:
            raise StopIteration
        return item
%}
  1. 原理:Python迭代器机制会自动捕获StopIteration异常来终止迭代,将异常抛出逻辑放在Python层,完全符合Python迭代规范,不会触发SWIG的错误检测。

方式二:通过C++异常映射实现

利用SWIG的异常映射功能,将C++异常转换为Python的StopIteration:

  1. 包含SWIG标准异常头,添加异常映射规则,修改__getitem__抛出C++异常:
%include <std_except.i>
%template(vectorModelDescriptor) com_cae::physiology::vector<::IModelDescriptor*>;

// 配置异常映射:将C++的out_of_range转换为Python的StopIteration
%exception {
    try {
        $action
    } catch (const std::out_of_range&) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }
}

%extend com_cae::physiology::vector<::IModelDescriptor*> {
    IModelDescriptor* __getitem__(unsigned int i) {
        if (i >= self->size()) {
            throw std::out_of_range("Index out of bounds");
        }
        return (*self)[i];
    }
}
  1. 原理:SWIG会自动捕获C++抛出的std::out_of_range异常,将其转换为Python的StopIteration,Python迭代器可正确识别并终止迭代。

额外优化:实现迭代器模式(更贴合Python习惯)

如果希望容器的迭代行为完全遵循Python标准,可实现__iter__方法返回专属迭代器:

%include <std_except.i>
%template(vectorModelDescriptor) com_cae::physiology::vector<::IModelDescriptor*>;

// 定义迭代器类
%inline %{
    class VectorModelDescriptorIterator {
    private:
        com_cae::physiology::vector<::IModelDescriptor*>* _vec;
        size_t _pos;
    public:
        VectorModelDescriptorIterator(com_cae::physiology::vector<::IModelDescriptor*>* vec)
            : _vec(vec), _pos(0) {}
        
        IModelDescriptor* __next__() {
            if (_pos >= _vec->size()) {
                throw std::out_of_range("End of iteration");
            }
            return (*_vec)[_pos++];
        }
    };
%}

// 为vector添加__iter__方法返回迭代器
%extend com_cae::physiology::vector<::IModelDescriptor*> {
    VectorModelDescriptorIterator* __iter__() {
        return new VectorModelDescriptorIterator(self);
    }
}

// 兼容Python2,将__next__重命名为next
%rename(next) VectorModelDescriptorIterator::__next__;

// 配置迭代器的异常映射
%exception VectorModelDescriptorIterator::__next__ {
    try {
        $action
    } catch (const std::out_of_range&) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }
}

这种方式支持for item in container:的原生遍历,也能兼容Python的各类迭代工具。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 15:55:07