pybind11使用教程笔记__4.2_bind STL container
STL containersAutomatic conversion当#include <pybind11/stl.h>,std::vector<>/std::deque<>/std::list<>/std::array<>, std::set<>/std::unordered_set<>, and std::ma
STL containers
Automatic conversion
当#include <pybind11/stl.h>
,std::vector<>/std::deque<>/std::list<>/std::array<>, std::set<>/std::unordered_set<>, and std::map<>/std::unordered_map<>
和 Python list, set and dict data structures
会自动进行转换。std::pair<> and std::tuple<>
在头文件pybind11/pybind11.h 中支持开箱即用。
这种数据类型转换的主要缺点是 必须进行内存拷贝,会影响程序的语法和性能。
Making opaque types
pybind11很依赖template matching mechanism
,来将STL数据结构(比如:vector, linked list, hash table 等数据结构)中的数据和参数 进行转换和返回。
然而这种内部转换的方法因为涉及拷贝操作,这不允许进行引用调用。这意味着什么呢?如下例:
void append_1(std::vector<int> &v) {
v.push_back(1);
}
从python中调用如上函数:
>>> v = [5, 6]
>>> append_1(v)
>>> print(v)
[5, 6]
如上所示,当将STL数据结构通过引用调用进行传递,C++中数据的改动并没有传回python端。类似的,在用def_readwrite
or def_readonly
来暴露C++ STL数据结构的时候也会出现这样的问题。
/* ... definition ... */
class MyClass {
std::vector<int> contents;
};
/* ... binding code ... */
py::class_<MyClass>(m, "MyClass")
.def(py::init<>())
.def_readwrite("contents", &MyClass::contents);
这种情况下,properties被设定为可读可写,但是python实际使用时不可写。
>>> m = MyClass()
>>> m.contents = [5, 6]
>>> print(m.contents)
[5, 6]
>>> m.contents.append(7)
>>> print(m.contents)
[5, 6]
最后,当数据非常大的时候,拷贝操作非常耗费资源。
Making opaque types
为了处理这种情况,pybind11 提供了PYBIND11_MAKE_OPAQUE(T)
的宏,这个宏使得类型转换不依赖于template-based conversion machinery of types。
这样一来是他们不透明。 opaque types 对象are never inspected or extracted, 因而可以通过引用进行传递。如将std::vector<int>
转为opaque类型, 在编写binding code前,先添加如下声明:
PYBIND11_MAKE_OPAQUE(std::vector<int>)
这个宏必须在程序顶部进行声明,并且不能在namespcae当中,因为这句宏会对模板的初始化进行重载,如果有多个编译单元,那么需要在每个源文件中使用std::vector<int>
前都要有这句宏,通常是共用一个头文件。
通常还会有一个class 来bind相关的operation,以便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__", [](const std::vector<int> &v) { return v.size(); })
.def("__iter__", [](std::vector<int> &v) {
return py::make_iterator(v.begin(), v.end());
}, py::keep_alive<0, 1>()) /* Keep vector alive while iterator is used */
// ....
pybind11 源码中 tests/test_opaque_types.cpp 有使用opaque完整的例子,且细节比较丰富。
更多推荐
所有评论(0)