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

pybind11绑定Eigen矩阵:读写异常与operator[]绑定问题

问题描述

C++实现与pybind11绑定代码

#include <vector>

#include <pybind11/eigen.h>
#include <Eigen/Dense>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>

namespace py = pybind11;

using EMatrixDbl = Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>;

class MyMap
{

public:
    MyMap(int i, int j)
    {
        m_matrices.resize(1);
        m_matrices[0].resize(i, j);
        m_matrices[0].setZero();
    }
    
    EMatrixDbl& operator[](int k)
    {
        return m_matrices[k];
    }
    
    EMatrixDbl& get(int k)
    {
        return m_matrices[k];
    }
    
    std::vector<EMatrixDbl> m_matrices;
    
    
};

PYBIND11_MODULE(MyMapPy, m) {
    
    py::class_<MyMap> c(m, "MyMap");
    
    c.def(py::init<int, int>());
    
    c.def("get", &MyMap::get, py::return_value_policy::reference_internal);

    c.def("get_lambda", [](MyMap& self, int k){
            EMatrixDbl& m_map = self[k];
            return m_map;
        }, py::return_value_policy::reference_internal);
}

Python测试代码

import MyMapPy
m = MyMapPy.MyMap(3, 3)

m.get(0)[0,0] = 1
m.get(0)  # [0,0] is 1

m.get_lambda(0)[0,0] = 2
m.get_lambda(0)  # [0,0] is always 1...

咨询问题

  1. 为何get_lambda方法无法实现同样的可写功能?
  2. 如何直接绑定MyMap::operator[]以提供可写绑定接口?

问题解答

1. get_lambda无法修改矩阵的原因

pybind11对Eigen类型有特殊的转换逻辑,当在lambda中返回EMatrixDbl&时,即使指定了reference_internal,转换器仍会默认创建矩阵的临时拷贝。这是因为lambda返回的引用没有被pybind11识别为类成员的直接关联引用,无法正确绑定到原对象的内存空间,导致Python拿到的是独立副本,修改操作不会同步到原矩阵。

而直接绑定成员函数get时,pybind11能明确识别返回值是类成员的引用,配合reference_internal策略,会返回指向原矩阵的视图,修改自然能同步到原对象。

2. 绑定MyMap::operator[]的方法

要实现可写的下标访问,只需将operator[]绑定为Python的__getitem__方法,并指定reference_internal返回策略。修改绑定代码如下:

PYBIND11_MODULE(MyMapPy, m) {
    
    py::class_<MyMap> c(m, "MyMap");
    
    c.def(py::init<int, int>());
    
    c.def("get", &MyMap::get, py::return_value_policy::reference_internal);

    // 可选:修复lambda版本,显式指定转换策略
    c.def("get_lambda", [](MyMap& self, int k){
            return py::cast(self[k], py::return_value_policy::reference_internal);
        });
    
    // 绑定operator[]为Python的__getitem__
    c.def("__getitem__", &MyMap::operator[], py::return_value_policy::reference_internal);
}

修改后,Python中可直接用下标访问并修改矩阵:

import MyMapPy
m = MyMapPy.MyMap(3, 3)
m[0][0,0] = 3
print(m[0]) # [0,0]的值为3,修改生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 20:56:35