Type conversions 类型转换
除了实现 python和C++的函数调用,两种语言之间的数据类型转换也很重要。通常有三种实现方法。
- 在程序的所有地方均使用C++的数据类型,这样的话相应的类型必须进行打包,这样才可以在python中进行调用。
- 在程序的所有地方均使用python的数据类型,这样的话相应的类型必须进行打包,这样才可以在C++中进行调用。
- 在C++程序中使用C++的数据类型,在python中使用python的数据类型。(pybind11 推荐)
type conversion 使用起来最自然,在各自的语言中使用原生的数据类型。但是这种方法的劣势是python和C++之间的相互调用数据必须要拷贝数据,因为相同的数据类型在python和C++中memory layout会有区别。
overview
-
Native type in C++, wrapper in Python
使用
py::class_
来将C++数据类型打包给python使用,具体见 Object-oriented code section。 底层的数据结构是C++原生的数据结构,py::class_
wrapper 提供了一个python使用的接口。对于一个object-like的数据类型,python使用时pybind11会自动给C++原生的数据结构添加外围warper。当从python中将数据取回到C++中时,会自动去掉外层的warper。
-
Wrapper in C++, native type in Python
和上面的情况正好相反,这种情况主要利用python的原生数据类型,比如tuple和list。主要可以通过py::object warper 系列
使C++能够使用python的原生数据类型。更多细节见: Python types section, 如下是一个简单的例子:void print_list(py::list my_list) { for (auto item : my_list) std::cout << item << " "; }
>>> print_list([1, 2, 3]) 1 2 3
上例中,python的数据类型list的数据格式没有被转变,只是在C++中使用 py::list class 将其包裹,其内核仍然是python的object。对py::list 对象进行copy 会像在python中一样做一个counting-reference的操作。将py::list 对象返回给python只需要将对象外边包裹的代码去除掉就可以了。
-
Converting between native C++ and Python types
在C++和python中各自使用各自的原生数据类型,交互时对各自原生的数据类型进行转换。void print_vector(const std::vector<int> &v) { for (auto item : v) std::cout << item << "\n"; }
>>> print_vector([1, 2, 3]) 1 2 3
这种情况下,pybind11 会在C++中构建一个新的
new std::vector<int>
,并从python 的list 中copy每个元素。新构建的std::vector
会被传入到print_vector()
中。在C++到python的数据流中,会发生类似的操作,python会创建一个list对象以匹配C++返回的数据。
很多类似的数据类型转换都是支持的,而且都是开包即用,如下表所示。这些数据类型转换非常方便,但是都需要copy数据。对于 small immutable types ,这样的方式挺好的,但是对于非常大的数据结构,copy数据的开销会非常大。可以通过手动添加warper代码的方式来避免这样的开销,需要花一些精力,这方面更多细节见 Making opaque types section.
List of all builtin conversions
如下数据类型可以直接进行数据类型转换。如需转换其他数据类型,见binding Object-oriented code.
Data type | Description | Header file |
---|---|---|
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 | Complex numbers | pybind11/complex.h |
std::array<T, Size> | STL static array | pybind11/stl.h |
std::vector STL | dynamic array | pybind11/stl.h |
std::deque STL | double-ended queue | pybind11/stl.h |
std::valarray | STL value array | pybind11/stl.h |
std::list | 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 | STL ordered set | pybind11/stl.h |
std::unordered_set | STL unordered set | pybind11/stl.h |
std::optional | STL optional type (C++17) | pybind11/stl.h |
std::experimental::optional | STL optional type (exp.) | pybind11/stl.h |
std::variant<…> | Type-safe union (C++17) | 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 |