Python and PyBind11

advanced
Published

November 16, 2024

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;
}

PYBIND11_MODULE(example, m) {
  m.doc() = "pybind11 example plugin"; // optional module docstring
  m.def("add", &add, "A function that adds two numbers");
}

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:

  1. Create a build directory and navigate into it: mkdir build && cd build
  2. Run CMake: cmake ..
  3. Compile the code: cmake --build .
  4. Install the module (optional, but recommended): cmake --install .

Now, you can use the module in your Python code:

python_script.py:

import example

result = example.add(5, 3)
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) {
    result.push_back(x * x);
  }
  return result;
}

PYBIND11_MODULE(advanced_example, m) {
  m.doc() = "Advanced pybind11 example plugin";
  m.def("square_vector", &square_vector, "Squares each element in a vector");
}

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.