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完整的例子,且细节比较丰富。

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐