文章目录
Pybind11
梳理一下 Pybind11 中 Eigen 和 STL 容器与 Python 交互的方式。需要先了解Functions章节中关于返回值和调用的规则。
Smart Pointers
STL 容器
Pybind11 已经自动支持 std::vector<>
/std::deque<>
/std::list<>
/std::array<>
/std::valarray<>
, std::set<>
/std::unordered_set<>
, and std::map<>
/std::unordered_map<>
和 Python list
, set
and dict
之间的转换。引用头文件 pybind11/pybind11.h
即可。如果想使用全部类,可以引用 pybind11/stl.h
Arbitrary nesting of any of these types is possible. 比如
std::vector<std::vector<int>>
问题
该方法的缺点在于每一次在 C++ 和 Python 之间转换时都要隐式转换,并且制作一份拷贝。所以下面的例子会失效
# Example 1
# C++
void append_1(std::vector<int> &v) {
v.push_back(1);
}
# python
>>> v = [5, 6]
>>> append_1(v)
>>> print(v)
[5, 6]
# Example 2
# C++
/* ... definition ... */
class MyClass {
std::vector<int> contents;
};
/* ... binding code ... */
py::class_<MyClass>(m, "MyClass")
.def(py::init<>())
.def_readwrite("contents", &MyClass::contents);
# Python
>>> m = MyClass()
>>> m.contents = [5, 6]
>>> print(m.contents)
[5, 6]
>>> m.contents.append(7)
>>> print(m.contents)
[5, 6]
上述例子 1 中,Python 向 C++ 传递 List 后,C++ 端制作了一份拷贝,所以两者使用的是不同的数据;例子 2 中,虽然pybind11将类的属性绑定到 Python,在 Python 端能够直接访问,但是例如 append
方法无法正常使用也是相同的原因。(Python 侧和 Cpp 侧并不是相同的实例)
Opaque 类
为了解决上述问题,Pybind11 提供了 PYBIND11_MAKE_OPAQUE(T)
宏定义将其变为 Opaque Type。Opaque Types 需要有对应的 class_
声明。例如:
// Opaque Type declaration
PYBIND11_MAKE_OPAQUE(std::vector<int>);
// Pybind11 Class
// 定义其需要暴露给 Python 的方法
py::class_<std::vector<int>>(m, "IntVector")
.def(py::init<>())
.def("clear", &std::vector<int>::clear)
.def("pop_back", &std::vector<int>::pop_back)
.def("__len__", [](