Skip to content

Commit f0b0df5

Browse files
committed
Directly compare 3 ways of moving data between C++ and Python
1 parent 67b52d8 commit f0b0df5

File tree

1 file changed

+71
-2
lines changed

1 file changed

+71
-2
lines changed

docs/advanced/cast/index.rst

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,74 @@
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
372

473
.. toctree::
574
:maxdepth: 1

0 commit comments

Comments
 (0)