Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

26 Jul 2020

Pybind11文档笔记【一】:类型转化

Type conversions

Overview

C++中的类可以用py::class_来包装成Python的类。Python中的类可以通过py::object暴露给C++。

在需要相互转化的时候,pybind会通过值来创建彼此的类型示例,比如:

void print_vector(const std::vector<int> &v) {
    for (auto item : v)
        std::cout << item << "\n";
}

print_vector在C++中接受的是vector,在python中接受的是list,vector和list的值会相互转化。转化过程会有计算损耗。

List of all builtin conversions列举了pybind11中定义的可以互转的类型。

Strings, bytes and Unicode conversions

python字符串转为c++的std::string或者char*时,会编码成UTF-8类型。反之,c++的字符串不带编码信息,所以需要确保是UTF-8类型的。会使用bytes.decode(‘utf-8’)将其转化为python的字符串。

如果使用的是python的bytes,那么可以直接对应到C++的std::string或者char*:

m.def("return_bytes",
    []() {
        std::string s("\xba\xd0\xba\xd0");  // Not valid UTF-8
        return py::bytes(s);  // Return the data without transcoding
    }
);

当然,也可以进行显示转化:

// This uses the Python C API to convert Latin-1 to Unicode
m.def("str_output",
    []() {
        std::string s = "Send your r\xe9sum\xe9 to Alice in HR"; // Latin-1
        py::str py_s = PyUnicode_DecodeLatin1(s.data(), s.length());
        return py_s;
    }
);

宽字符会被对应到UTF-16或者UTF-32 。

对于单个字符为参数的c++函数,Python字符串中的第一个字符会被传入。

对于可能需要多个Unicode码点表示的grapheme,最好在规范化之后传给C++:

>>> example.pass_wchar(unicodedata.normalize('NFC', combining_e_acute))
'é'

不能保证所有的grapheme都能这样处理。

C++17引入的string_view会被自动支持以及转化。

STL containers

包含了pybind11/stl.h之后,许多标准容器都能自动转化。但是这种转化是需要进行传值转化的。

C++17的std::optional<>也是支持的。

pybind默认会通过模板匹配来对容器的内容进行检查并提供相应的传值支持,但是不提供传引用支持。这可能会导致一些问题:

void append_1(std::vector<int> &v) {
   v.push_back(1);
}
>>> v = [5, 6]
>>> append_1(v)
>>> print(v)
[5, 6] # 而不是[5, 6, 1]

如果想把容器整体作为一个对象来传递引用,可以使用类似下面的声明:

PYBIND11_MAKE_OPAQUE(std::vector<int>);

pybind11/stl_bind.h为把容器对象转化为python对象提供一些支持:

// Don't forget this
#include <pybind11/stl_bind.h>

PYBIND11_MAKE_OPAQUE(std::vector<int>);
PYBIND11_MAKE_OPAQUE(std::map<std::string, double>);

// ...

// later in binding code:
py::bind_vector<std::vector<int>>(m, "VectorInt");
py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");

Functional

介绍如何处理lambda和std::function。

Chrono

计时相关。

Eigen

Eigen是C++线性代数处理库。本篇介绍pybind11如何支持它。

Custom type casters

可以使用Python C API来对类型转化进行更高级地自定义。

其他参考

(本篇完)

comments powered by Disqus