Seamless operability between C++11 and Python for creating Python bindings of existing C++ code
—
pybind11 provides seamless integration with C++ Standard Template Library (STL) containers, offering both automatic conversion and explicit container binding utilities. This enables efficient data exchange between C++ containers and Python collections.
Include <pybind11/stl.h> for automatic conversion between STL containers and Python collections.
// Automatic conversions (enabled by including pybind11/stl.h)
// std::vector<T> <-> Python list
// std::array<T, N> <-> Python list
// std::list<T> <-> Python list
// std::deque<T> <-> Python list
// std::set<T> <-> Python set
// std::unordered_set<T> <-> Python set
// std::map<K, V> <-> Python dict
// std::unordered_map<K, V> <-> Python dict
// std::pair<T1, T2> <-> Python tuple
// std::tuple<Ts...> <-> Python tupleBind STL containers as Python classes for more control and performance.
// Vector binding
template<typename Vector, typename... Options>
class_<Vector> bind_vector(module_ &m, const char *name, const Options&... options);
// Map binding
template<typename Map, typename... Options>
class_<Map> bind_map(module_ &m, const char *name, const Options&... options);When using explicit binding, containers get Python-like methods.
// Vector methods (when using bind_vector)
class BoundVector {
public:
// Python list-like interface
void append(const T& value);
void clear();
void extend(const BoundVector& other);
void insert(size_t index, const T& value);
T pop();
T pop(size_t index);
void remove(const T& value);
// Python indexing and slicing
T& operator[](size_t index);
BoundVector operator[](slice s);
// Python methods
size_t count(const T& value) const;
size_t index(const T& value) const;
void reverse();
void sort();
// Standard container methods
size_t size() const;
bool empty() const;
iterator begin();
iterator end();
};
// Map methods (when using bind_map)
class BoundMap {
public:
// Python dict-like interface
void clear();
bool contains(const K& key) const;
V get(const K& key) const;
V get(const K& key, const V& default_value) const;
list items() const;
list keys() const;
V pop(const K& key);
V pop(const K& key, const V& default_value);
void popitem();
void setdefault(const K& key, const V& default_value);
void update(const BoundMap& other);
list values() const;
// Python indexing
V& operator[](const K& key);
// Standard container methods
size_t size() const;
bool empty() const;
iterator begin();
iterator end();
};STL containers work seamlessly with smart pointers.
// Automatic conversion support for smart pointers in containers
// std::vector<std::shared_ptr<T>> <-> Python list
// std::vector<std::unique_ptr<T>> <-> Python list (with move semantics)
// std::map<K, std::shared_ptr<V>> <-> Python dictAccess to STL iterators from Python when using explicit binding.
// Iterator binding (automatically included with container binding)
template<typename Iterator>
class iterator_wrapper {
public:
Iterator& operator++();
bool operator==(const iterator_wrapper& other) const;
bool operator!=(const iterator_wrapper& other) const;
auto operator*() const;
};Support for C++17 optional and variant types.
// std::optional<T> support (include pybind11/stl.h)
// Converts to Python None or the contained value
// std::variant<Ts...> support
// Automatically selects appropriate Python type based on active variant member#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <vector>
#include <map>
namespace py = pybind11;
std::vector<int> create_vector() {
return {1, 2, 3, 4, 5};
}
void process_vector(const std::vector<std::string>& vec) {
for (const auto& item : vec) {
std::cout << item << std::endl;
}
}
std::map<std::string, int> create_map() {
return {{"apple", 5}, {"banana", 3}, {"orange", 8}};
}
PYBIND11_MODULE(example, m) {
// Automatic conversion - vectors become Python lists
m.def("create_vector", &create_vector);
m.def("process_vector", &process_vector);
// Automatic conversion - maps become Python dicts
m.def("create_map", &create_map);
}#include <pybind11/pybind11.h>
#include <pybind11/stl_bind.h>
#include <vector>
namespace py = pybind11;
PYBIND11_MODULE(example, m) {
// Bind vector as a Python class
py::bind_vector<std::vector<int>>(m, "VectorInt");
py::bind_vector<std::vector<std::string>>(m, "VectorString");
// Bind map as a Python class
py::bind_map<std::map<std::string, int>>(m, "MapStringInt");
// Custom container with additional methods
py::class_<std::vector<double>>(m, "VectorDouble")
.def(py::init<>())
.def("push_back", &std::vector<double>::push_back)
.def("size", &std::vector<double>::size)
.def("__len__", &std::vector<double>::size)
.def("__iter__", [](const std::vector<double> &v) {
return py::make_iterator(v.begin(), v.end());
}, py::keep_alive<0, 1>());
}#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
// Nested container function
std::vector<std::vector<int>> create_matrix(int rows, int cols) {
std::vector<std::vector<int>> matrix(rows, std::vector<int>(cols, 0));
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < cols; ++j) {
matrix[i][j] = i * cols + j;
}
}
return matrix;
}
// Complex nested structure
std::map<std::string, std::vector<std::pair<int, double>>> complex_data() {
return {
{"series1", {{1, 1.1}, {2, 2.2}, {3, 3.3}}},
{"series2", {{10, 10.1}, {20, 20.2}, {30, 30.3}}}
};
}
PYBIND11_MODULE(example, m) {
m.def("create_matrix", &create_matrix);
m.def("complex_data", &complex_data);
}#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <memory>
#include <vector>
namespace py = pybind11;
class Widget {
public:
Widget(const std::string& name) : name_(name) {}
const std::string& name() const { return name_; }
private:
std::string name_;
};
std::vector<std::shared_ptr<Widget>> create_widgets() {
return {
std::make_shared<Widget>("widget1"),
std::make_shared<Widget>("widget2"),
std::make_shared<Widget>("widget3")
};
}
PYBIND11_MODULE(example, m) {
py::class_<Widget>(m, "Widget")
.def(py::init<const std::string&>())
.def("name", &Widget::name);
// Automatic conversion of vector of shared_ptr
m.def("create_widgets", &create_widgets);
}#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
namespace py = pybind11;
class NumberGenerator {
int current_, max_;
public:
NumberGenerator(int max) : current_(0), max_(max) {}
// Make it iterable
NumberGenerator& iter() { return *this; }
int next() {
if (current_ >= max_) throw py::stop_iteration();
return current_++;
}
};
PYBIND11_MODULE(example, m) {
py::class_<NumberGenerator>(m, "NumberGenerator")
.def(py::init<int>())
.def("__iter__", &NumberGenerator::iter,
py::return_value_policy::reference_internal)
.def("__next__", &NumberGenerator::next);
}// Automatic conversion (pybind11/stl.h)
// Pros: Simple, works out of the box
// Cons: Always copies data, memory overhead
std::vector<int> get_data() { return large_vector; } // Always copies
// Explicit binding (pybind11/stl_bind.h)
// Pros: Direct access, no copying, Python-like interface
// Cons: More setup required
py::bind_vector<std::vector<int>>(m, "VectorInt"); // Direct accessclass DataManager {
std::vector<double> data_;
public:
// Return reference to avoid copying
const std::vector<double>& get_data() const { return data_; }
std::vector<double>& get_mutable_data() { return data_; }
};
PYBIND11_MODULE(example, m) {
py::class_<DataManager>(m, "DataManager")
.def("get_data", &DataManager::get_data,
py::return_value_policy::reference_internal)
.def("get_mutable_data", &DataManager::get_mutable_data,
py::return_value_policy::reference_internal);
}namespace pybind11 {
// Container binding functions (from stl_bind.h)
template<typename Vector, typename... Options>
class_<Vector> bind_vector(module_ &m, const char *name, const Options&... options);
template<typename Map, typename... Options>
class_<Map> bind_map(module_ &m, const char *name, const Options&... options);
template<typename Deque, typename... Options>
class_<Deque> bind_deque(module_ &m, const char *name, const Options&... options);
// Iterator utilities
template<typename Iterator>
class iterator_wrapper;
template<typename Iterator>
auto make_iterator(Iterator first, Iterator last);
template<typename Iterator>
auto make_key_iterator(Iterator first, Iterator last);
template<typename Iterator>
auto make_value_iterator(Iterator first, Iterator last);
}Install with Tessl CLI
npx tessl i tessl/pypi-pybind11