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

如何在SWIG中让Python无缝处理std::span<uint8_t>输出参数

实现Python无缝操作SWIG导出的std::span<uint8_t>输出参数

要实现Python端无需辅助函数、直接操作std::span<uint8_t>对象的需求,你可以通过SWIG的%extend扩展功能和director特性来完成,以下是具体实现方案:

SWIG接口文件配置

创建或修改你的SWIG接口文件(比如example.i),添加以下内容:

%module example

%{
#include <span>
#include <vector>
#include <algorithm>
#include <Python.h>
%}

// 为std::span<uint8_t>扩展Python可调用的方法
%extend std::span<uint8_t> {
    // 暴露span的size方法给Python
    size_t size() const {
        return $self->size();
    }

    // 实现Python风格的赋值操作,支持bytes/bytearray类型
    void __assign__(const PyObject* data) {
        if (PyBytes_Check(data)) {
            const char* bytes_ptr = PyBytes_AsString(data);
            Py_ssize_t data_len = PyBytes_Size(data);
            if (static_cast<size_t>(data_len) > $self->size()) {
                PyErr_SetString(PyExc_ValueError, "数据长度超过buffer容量");
                return;
            }
            std::copy(bytes_ptr, bytes_ptr + data_len, $self->data());
        } else if (PyByteArray_Check(data)) {
            char* bytes_ptr = PyByteArray_AsString(data);
            Py_ssize_t data_len = PyByteArray_Size(data);
            if (static_cast<size_t>(data_len) > $self->size()) {
                PyErr_SetString(PyExc_ValueError, "数据长度超过buffer容量");
                return;
            }
            std::copy(bytes_ptr, bytes_ptr + data_len, $self->data());
        } else {
            PyErr_SetString(PyExc_TypeError, "仅支持bytes或bytearray类型赋值");
            return;
        }
    }
}

// 定义你的纯虚类及SWIG包装类
%inline %{
class DataFiller {
public:
    virtual ~DataFiller() = default;
    virtual void fill_buffer(size_t offset, std::span<uint8_t> buffer) = 0;
};

// 用于桥接Python继承的包装类
class DataFillerWrapper : public DataFiller {
public:
    virtual void fill_buffer(size_t offset, std::span<uint8_t> buffer) override {
        SWIG_Python_OverloadCallFunc(swig_get_self(), "fill_buffer", "nO", offset, &buffer);
    }
};
%}

// 启用director特性,允许Python继承C++纯虚类
%feature("director") DataFiller;

关键部分说明

  1. %extend std::span<uint8_t>:给SWIG生成的std::span<uint8_t> Python包装类扩展两个核心方法:

    • size():直接返回span的容量,对应Python端的buffer.size()调用
    • __assign__:重载Python的赋值操作,将bytes/bytearray类型的数据复制到span指向的内存区域,同时做容量检查避免越界
  2. Director特性:通过%feature("director")启用SWIG的回调机制,让Python可以继承并实现C++的纯虚函数fill_buffer。

Python端使用代码

完成SWIG编译后,Python端可以直接按预期方式实现函数:

import example

class PythonDataFiller(example.DataFiller):
    def __init__(self, resource_file):
        super().__init__()
        self.resource_file = resource_file

    def fill_buffer(self, offset, buffer):
        with open(self.resource_file, 'rb') as file:
            file.seek(offset)
            # 直接调用buffer.size()获取容量,读取数据后直接赋值给buffer
            buffer = file.read(buffer.size())

# 示例使用
data_filler = PythonDataFiller("your_resource.bin")
# 假设C++端会调用data_filler的fill_buffer方法并传入预分配的span

方案优势

  • 消除了辅助函数的依赖,Python代码更简洁直观
  • 完全贴合Python的语法习惯,操作方式符合Python开发者预期
  • 内置容量检查,避免内存越界风险

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 06:01:45