|
1 |
| -Casting data types |
2 |
| -################## |
| 1 | +Type conversions |
| 2 | +################ |
| 3 | + |
| 4 | +There are 3 mechanisms that pybind11 uses to move data between C++ and Python. |
| 5 | +We'll take a quick look at each one to get an overview of what's happening. |
| 6 | + |
| 7 | +.. rubric:: 1. Native type in C++, wrapper in Python |
| 8 | + |
| 9 | +Exposing a custom C++ type using :class:`py::class_` was covered in detail in |
| 10 | +the :doc:`/classes` section. There, the underlying data structure is always the |
| 11 | +original C++ class while the :class:`py::class_` wrapper provides a Python |
| 12 | +interface. Internally, when an object like this is sent from C++ to Python, |
| 13 | +pybind11 will just add the outer wrapper layer over the native C++ object. |
| 14 | +Getting it back from Python is just a matter of peeling off the wrapper. |
| 15 | + |
| 16 | +.. rubric:: 2. Wrapper in C++, native type in Python |
| 17 | + |
| 18 | +This is the exact opposite situation. Now, we have a type which is native to |
| 19 | +Python, like a ``tuple`` or a ``list``. One way to get this data into C++ is |
| 20 | +with the :class:`py::object` family of wrappers. These are explained in more |
| 21 | +detail in the :doc:`/advanced/pycpp/object` section. We'll just give a quick |
| 22 | +example here: |
| 23 | + |
| 24 | +.. code-block:: cpp |
| 25 | +
|
| 26 | + void print_list(py::list my_list) { |
| 27 | + for (auto item : my_list) |
| 28 | + std::cout << item << " "; |
| 29 | + } |
| 30 | +
|
| 31 | +.. code-block:: pycon |
| 32 | +
|
| 33 | + >>> print_list([1, 2, 3]) |
| 34 | + 1 2 3 |
| 35 | +
|
| 36 | +The Python ``list`` is not converted in any way -- it's just wrapped in a C++ |
| 37 | +:class:`py::list` class. At its core it's still a Python object. Copying a |
| 38 | +:class:`py::list` will do the usual reference-counting like in Python. |
| 39 | +Returning the object to Python will just remove the thin wrapper. |
| 40 | + |
| 41 | +.. rubric:: 3. Converting between native C++ and Python types |
| 42 | + |
| 43 | +In the previous two cases we had a native type in one language and a wrapper in |
| 44 | +the other. Now, we have native types on both sides and we convert between them. |
| 45 | + |
| 46 | +.. code-block:: cpp |
| 47 | +
|
| 48 | + void print_vector(const std::vector<int> &v) { |
| 49 | + for (auto item : v) |
| 50 | + std::cout << item << "\n"; |
| 51 | + } |
| 52 | +
|
| 53 | +.. code-block:: pycon |
| 54 | +
|
| 55 | + >>> print_vector([1, 2, 3]) |
| 56 | + 1 2 3 |
| 57 | +
|
| 58 | +In this case, pybind11 will construct a new ``std::vector<int>`` and copy each |
| 59 | +element from the Python ``list``. The newly constructed object will be passed |
| 60 | +to ``print_vector``. The same thing happens in the other direction: a new |
| 61 | +``list`` is made to match the value returned from C++. |
| 62 | + |
| 63 | +Lots of these conversions are supported out of the box, as shown in the table |
| 64 | +below. They are very convenient, but keep in mind that these conversions are |
| 65 | +fundamentally based on copying data. This is perfectly fine for small immutable |
| 66 | +types but it may become quite expensive for large data structures. This can be |
| 67 | +avoided by overriding the automatic conversion with a custom wrapper (i.e. the |
| 68 | +above-mentioned approach 1). This requires some manual effort and more details |
| 69 | +are available in the :ref:`opaque` section. |
| 70 | + |
| 71 | +.. rubric:: Supported automatic conversions |
3 | 72 |
|
4 | 73 | .. toctree::
|
5 | 74 | :maxdepth: 1
|
|
0 commit comments