Python’s ease of use and extensive libraries make it a favorite for rapid prototyping and scripting. However, when performance becomes critical, the speed of C++ can be indispensable. PyBind11 provides a seamless way to bridge this gap, allowing you to integrate your high-performance C++ code directly into your Python projects. This post will explore how to use PyBind11 to enhance your Python applications with the power of C++.
Why Use PyBind11?
Before diving into the code, let’s understand why PyBind11 is a preferred choice for Python-C++ integration:
- Simplicity: PyBind11 boasts a remarkably clean and intuitive API. You don’t need to grapple with complex build systems or intricate boilerplate code.
- Performance: By offloading computationally intensive tasks to C++, you can significantly boost your Python application’s speed.
- Ease of use: The syntax is straightforward, minimizing the learning curve for both Python and C++ developers.
- Header-only library: PyBind11 is a header-only library, simplifying the installation process – no need for separate compilation or installation steps.
Setting up your environment
To get started, you’ll need a C++ compiler (like g++) and a Python installation with development headers (often installed via a package like python3-dev
on Debian/Ubuntu systems or python-devel
on Fedora/CentOS/RHEL). You’ll also need CMake, a build system that simplifies the process of compiling your code.
A Simple Example: Adding Two Numbers
Let’s start with a basic example: a C++ function that adds two numbers, exposed to Python via PyBind11.
cpp_module.cpp:
#include <pybind11/pybind11.h>
namespace py = pybind11;
int add(int a, int b) {
return a + b;
}
(example, m) {
PYBIND11_MODULE.doc() = "pybind11 example plugin"; // optional module docstring
m.def("add", &add, "A function that adds two numbers");
m}
CMakeLists.txt:
cmake_minimum_required(VERSION 3.10)
project(example)
add_subdirectory(pybind11) # Path to your pybind11 directory
add_library(example SHARED cpp_module.cpp)
target_link_libraries(example pybind11::pybind11)
install(TARGETS example DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
install(FILES example.py DESTINATION ${CMAKE_INSTALL_PREFIX}/lib)
Building and using the module:
- Create a
build
directory and navigate into it:mkdir build && cd build
- Run CMake:
cmake ..
- Compile the code:
cmake --build .
- Install the module (optional, but recommended):
cmake --install .
Now, you can use the module in your Python code:
python_script.py:
import example
= example.add(5, 3)
result print(f"The sum is: {result}")
Running python python_script.py
will output “The sum is: 8”.
A More Advanced Example: Vector Operations
Let’s create a more sophisticated example involving vectors:
cpp_module.cpp:
#include <pybind11/pybind11.h>
#include <vector>
namespace py = pybind11;
std::vector<double> square_vector(const std::vector<double>& vec) {
std::vector<double> result;
for (double x : vec) {
.push_back(x * x);
result}
return result;
}
(advanced_example, m) {
PYBIND11_MODULE.doc() = "Advanced pybind11 example plugin";
m.def("square_vector", &square_vector, "Squares each element in a vector");
m}
Remember to adjust your CMakeLists.txt
to reflect the new module name (advanced_example
). This example showcases how easily PyBind11 handles standard C++ containers like std::vector
, making data transfer between C++ and Python seamless. You can then use this function in a similar Python script as before, passing and receiving vectors. This demonstrates the power and flexibility PyBind11 offers for more complex data structures.
Classes and Object-Oriented Programming
PyBind11 also supports creating and using C++ classes within your Python code, enabling seamless interaction between object-oriented code in both languages. This extends the capabilities further, allowing you to use advanced features from both environments. We will cover classes and object-oriented programming in a future blog post.