pybind11学习 异常转换和类型转换
本文主要记录官方文档中 EXCEPTIONS 和 TYPE CONVERSIONS 一章的学习笔记。
[TOC]
一 异常转换
1.1 C++内置异常到Python异常的转换
当Python通过pybind11调用C++代码时,pybind11将捕获C++异常,并将其翻译为对应的Python异常后抛出,这样Python代码就能够处理它们。
C++抛出的异常 | 转换到Python的异常类型 |
---|---|
std::exception |
RuntimeError |
std::bad_alloc |
MemoryError |
std::domain_error |
ValueError |
std::invalid_argument |
ValueError |
std::length_error |
ValueError |
std::out_of_range |
IndexError |
std::range_error |
ValueError |
std::overflow_error |
OverflowError |
pybind11::stop_iteration |
StopIteration |
pybind11::index_error |
IndexError |
pybind11::key_error |
KeyError |
pybind11::value_error |
ValueError |
pybind11::type_error |
TypeError |
pybind11::buffer_error |
BufferError |
pybind11::import_error |
ImportError |
pybind11::attribute_error |
AttributeError |
其他异常 | RuntimeError |
当入参不能转化为Python对象时,
handle::call()
将抛出pybind11::cast_error
异常。
1.2 注册自定义异常转换
当上述的异常转换不能满足我们需求时,我们可以注册一个自定义的C++到Python的异常转换。使用下面的方法:
1 |
|
这个调用在指定模块创建了一个名称为PyExp的Python异常,并自动将CppExp相关的异常转换为PyExp异常。
1.3 在C++中处理Python异常
[1.1节](##1.1 C++内置异常到Python异常的转换)是C++异常到Python异常的转换,这一节为Python异常到C++异常的转换。
在Python中抛出的异常 | 作为C++异常类型抛出 |
---|---|
Any Python Exception |
pybind11::error_already_set |
下面例子演示了如何在C++侧处理捕获到的Python异常。
1 |
|
二 类型转换
2.1 包装和类型转换
在C++中使用原生的Python类型(如list或tuple等),我们有两种方式。第一,通过包装,将原生Python类型通过py::object
派生包装器包装,在C++中撕掉包装后再使用,其核心仍然是一个Python对象。示例如下:
1 |
|
1 |
|
其中
py::list
便是Python原生类型list
在C++中的包装类型。
第二种方式是通过类型转换,将原生Python类型转换成原生C++类型后再在C++侧使用,即两侧都使用各自的原生类型。示例如下:
1 |
|
1 |
|
上面这个例子中,Python原生类型list
到C++原生类型vector
的转换时通过pybind11自动完成的。更多开箱即用(pybind11内置转换,不需要我们自定义类型转换)的类型转换见下表。
数据类型 | 描述 | 头文件 |
---|---|---|
int8_t , uint8_t |
8-bit integers | pybind11/pybind11.h |
int16_t , uint16_t |
16-bit integers | pybind11/pybind11.h |
int32_t , uint32_t |
32-bit integers | pybind11/pybind11.h |
int64_t , uint64_t |
64-bit integers | pybind11/pybind11.h |
ssize_t , size_t |
Platform-dependent size | pybind11/pybind11.h |
float , double |
Floating point types | pybind11/pybind11.h |
bool |
Two-state Boolean type | pybind11/pybind11.h |
char |
Character literal | pybind11/pybind11.h |
char16_t |
UTF-16 character literal | pybind11/pybind11.h |
char32_t |
UTF-32 character literal | pybind11/pybind11.h |
wchar_t |
Wide character literal | pybind11/pybind11.h |
const char * |
UTF-8 string literal | pybind11/pybind11.h |
const char16_t * |
UTF-16 string literal | pybind11/pybind11.h |
const char32_t * |
UTF-32 string literal | pybind11/pybind11.h |
const wchar_t * |
Wide string literal | pybind11/pybind11.h |
std::string |
STL dynamic UTF-8 string | pybind11/pybind11.h |
std::u16string |
STL dynamic UTF-16 string | pybind11/pybind11.h |
std::u32string |
STL dynamic UTF-32 string | pybind11/pybind11.h |
std::wstring |
STL dynamic wide string | pybind11/pybind11.h |
std::string_view , std::u16string_view , etc. |
STL C++17 string views | pybind11/pybind11.h |
std::pair<T1, T2> |
Pair of two custom types | pybind11/pybind11.h |
std::tuple<...> |
Arbitrary tuple of types | pybind11/pybind11.h |
std::reference_wrapper<...> |
Reference type wrapper | pybind11/pybind11.h |
std::complex<T> |
Complex numbers | pybind11/complex.h |
std::array<T, Size> |
STL static array | pybind11/stl.h |
std::vector<T> |
STL dynamic array | pybind11/stl.h |
std::deque<T> |
STL double-ended queue | pybind11/stl.h |
std::valarray<T> |
STL value array | pybind11/stl.h |
std::list<T> |
STL linked list | pybind11/stl.h |
std::map<T1, T2> |
STL ordered map | pybind11/stl.h |
std::unordered_map<T1, T2> |
STL unordered map | pybind11/stl.h |
std::set<T> |
STL ordered set | pybind11/stl.h |
std::unordered_set<T> |
STL unordered set | pybind11/stl.h |
std::optional<T> |
STL optional type (C++17) | pybind11/stl.h |
std::experimental::optional<T> |
STL optional type (exp.) | pybind11/stl.h |
std::variant<...> |
Type-safe union (C++17) | pybind11/stl.h |
std::filesystem::path<T> |
STL path (C++17) 1 | pybind11/stl.h |
std::function<...> |
STL polymorphic function | pybind11/functional.h |
std::chrono::duration<...> |
STL time duration | pybind11/chrono.h |
std::chrono::time_point<...> |
STL date/time | pybind11/chrono.h |
Eigen::Matrix<...> |
Eigen: dense matrix | pybind11/eigen.h |
Eigen::Map<...> |
Eigen: mapped memory | pybind11/eigen.h |
Eigen::SparseMatrix<...> |
Eigen: sparse matrix | pybind11/eigen.h |
注意:上述的内置转换都是基于数据拷贝的。这对小型的不变的类型相当友好,对于大型数据结构则相当昂贵。这可以通过自定义包装类型重载自动转换来解决。
2.2 STL容器
包含头文件pybind11/stl.h
,将支持如下内置转换:
C++ | Python |
---|---|
std::vector<> /std::deque<> /std::list<> /std::array<> /std::valarray<> |
list |
std::set<> /std::unordered_set<> |
set |
std::map<> /std::unordered_map<> |
dict |
这些类型任意嵌套都是可以自动转换的。
2.2.1 绑定STL容器
有时,我们需要创建STL容器的Python绑定,使在Python中将STL容器作为对象进行使用。
1 |
|
pybind11提供了PYBIND11_MAKE_OPAQUE(T)
来禁用基于模板的类型转换机制,从而使他们变得不透明(opaque)。opaque对象的内容永远不会被检查或提取,因此它们可以通过引用传递。这样一来避免对大型列表进行拷贝操作带来的耗时。
2.3 函数对象
如果一个将函数对象作为函数的参数,那么设计Python中函数和C++函数对象之间的转换。有一如下示例函数,接收一函数对象,返回一函数对象:
1 |
|
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!