如何通过pybind11将std::map导出为可点访问的对象而非字典?
如何在pybind11中让std::map支持Python点语法访问
默认情况下,pybind11会将C++的std::map直接映射为Python的dict,只能通过下标[]访问元素,示例代码如下:
struct A { std::map<std::string, int> attributes; A() { attributes["x"] = 1; attributes["y"] = 2; } }; PYBIND11_MODULE(Example, m) { py::class_<A>(m, "A") .def_readonly("attributes", &A::attributes); }
在Python中只能这样访问:
a.attributes["x"] a.attributes["y"]
要实现a.attributes.x这类点语法访问,你可以通过给std::map绑定自定义的__getattr__和__setattr__方法来实现,具体代码如下:
C++绑定代码
#include <pybind11/pybind11.h> #include <map> #include <string> namespace py = pybind11; struct A { std::map<std::string, int> attributes; A() { attributes["x"] = 1; attributes["y"] = 2; } }; // 为std::map<std::string, int>实现支持点语法的绑定 void bind_string_int_map(py::module_& m) { py::class_<std::map<std::string, int>>(m, "StringIntMap") .def(py::init<>()) // 处理点语法获取属性 .def("__getattr__", [](const std::map<std::string, int>& self, const std::string& name) { auto iter = self.find(name); if (iter != self.end()) { return iter->second; } throw py::attribute_error("属性 '" + name + "' 不存在"); }) // 处理点语法设置属性 .def("__setattr__", [](std::map<std::string, int>& self, const std::string& name, int value) { self[name] = value; }) // 可选:保留dict常用方法,比如获取键、键值对列表 .def("keys", [](const std::map<std::string, int>& self) { py::list keys_list; for (const auto& pair : self) { keys_list.append(pair.first); } return keys_list; }) .def("items", [](const std::map<std::string, int>& self) { py::list items_list; for (const auto& pair : self) { items_list.append(py::make_tuple(pair.first, pair.second)); } return items_list; }); } PYBIND11_MODULE(Example, m) { bind_string_int_map(m); py::class_<A>(m, "A") .def(py::init<>()) .def_readonly("attributes", &A::attributes); }
Python访问示例
import Example a = Example.A() # 点语法获取属性 print(a.attributes.x) # 输出 1 print(a.attributes.y) # 输出 2 # 点语法设置属性 a.attributes.z = 3 print(a.attributes.z) # 输出 3 # 调用保留的dict方法 print(a.attributes.keys()) # 输出 ['x', 'y', 'z']
实现原理
通过给std::map的绑定类添加__getattr__和__setattr__方法,让Python解释器在处理点语法访问时,自动调用这些函数来查询或修改std::map中的键值对,同时还可以保留原有dict的常用方法,兼顾兼容性。
内容的提问来源于stack exchange,提问作者tmlen
相关产品推荐
相关产品推荐

