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 |