Última actualización:2026-10-12
Acelerar Python con pybind11¶
Normalmente, para las operaciones costosas esperamos implementarlas en C++ y luego llamar a las interfaces correspondientes desde Python, o bien, por culpa de la biblioteca subyacente, necesitamos dar soporte a una API Python externa; en definitiva, solemos necesitar acceder a C++ desde Python. ¿Cómo lograrlo?
Hay bastantes métodos; en esta sección tomamos pybind11 como ejemplo e introducimos una plantilla completa de proyecto de ingeniería, para que, si más adelante tienes esta necesidad, puedas modificarla partiendo de ella.
Nota: (versión para perezosos) todo el código de esta sección también está en la comunidad 星球.
1. Expansión de la macro¶
Supongamos: tomamos como ejemplo una ordenación relativamente costosa; si queremos escribir una ordenación en C++ y luego usarla en Python, ¿cómo escribirla?
El programa C++ es bastante sencillo: basta con exponer una interfaz que haga la ordenación, por ejemplo:
std::vector<int> sort_vector(const std::vector<int>& input) {
std::vector<int> result = input;
std::sort(result.begin(), result.end());
return result;
}
Entonces surge la pregunta: para Pybind11, ¿cómo usar esta interfaz?
Basta usar la macro de pybind11 para definir un módulo; por ejemplo:
PYBIND11_MODULE(sort_module, m) {
m.doc() = "pybind11 example plugin"; // Optional module docstring
m.def("sort_vector", &sort_vector, "A function that sorts a list of integers");
}
Tras la expansión de la macro queda: PyInit_sort_module
Cuando en python hacemos import de la biblioteca xxx, el intérprete de Python carga un módulo de extensión escrito en C/C++ e invoca automáticamente la función de entrada, y esa función de entrada es justamente la PyInit_sort_module siguiente:
static ::pybind11::module_::module_def pybind11_module_def_sort_module [[maybe_unused]];
[[maybe_unused]] static void pybind11_init_sort_module(::pybind11::module_ &);
extern "C" [[maybe_unused]] __attribute__((visibility("default"))) PyObject *PyInit_sort_module();
extern "C" __attribute__((visibility("default"))) PyObject *PyInit_sort_module() {
{
const char *compiled_ver = "3" "." "11";
const char *runtime_ver = Py_GetVersion();
size_t len = std::strlen(compiled_ver);
if (std::strncmp(runtime_ver, compiled_ver, len) != 0 || (runtime_ver[len] >= '0' && runtime_ver[len] <= '9')) {
PyErr_Format(PyExc_ImportError,
"Python version mismatch: module was compiled for Python %s, "
"but the interpreter version is incompatible: %s.",
compiled_ver, runtime_ver);
return nullptr;
}
}
pybind11::detail::get_internals();
auto m = ::pybind11::module_::create_extension_module("sort_module", nullptr, &pybind11_module_def_sort_module);
try {
pybind11_init_sort_module(m);
return m.ptr();
} catch (pybind11::error_already_set & e) {
pybind11::raise_from(e, PyExc_ImportError, "initialization failed");
return nullptr;
} catch (const std::exception &e) {
::pybind11::set_error(PyExc_ImportError, e.what());
return nullptr;
}
}
void pybind11_init_sort_module(::pybind11::module_ & m) {
m.doc() = "pybind11 example plugin";
m.def("sort_vector", &sort_vector, "A function that sorts a list of integers");
}
Por eso, si no usamos esta macro, al hacer import de la biblioteca obtendremos un error:
>>> import sort_module
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: dynamic module does not define module export function (PyInit_sort_module)
2. CMake + pybind11¶
El uso de pybind11 en C++ es el siguiente:
- Archivos de cabecera
- Macro
¿Y cómo descargar y enlazar pybind11 en cmake?
Basta con usar el módulo FetchContent; por ejemplo:
Después añade tu módulo en el CMakeLists:
cmake descargará pybingd11 por ti y además lo dejará compilado.
3. Uso¶
Lo anterior genera un so; instálalo en el directorio site-packages de python y, al hacer import, se reconocerá. A continuación se demuestra nuestro módulo personalizado:
import sort_module
def test_sort():
input_list = [5, 2, 3, 1, 4]
sorted_list = sort_module.sort_vector(input_list)
print(f"Original list: {input_list}")
print(f"Sorted list: {sorted_list}")
if __name__ == "__main__":
test_sort()
Ejecución:
Temas relacionados¶
- Implementando C++ FnOnce a mano | C++那些事
- Pequeño proyecto gRPC en C++ | C++那些事
- Comunicación entre procesos en C++ en la práctica | C++那些事
- Demo de servicio de URL cortas en C++ | C++那些事
- C++17 y SQLite para medir el tamaño de directorios | C++那些事
- Pruebas de rendimiento con Google Benchmark | C++那些事
- Servidor HTTP con corrutinas de C++20 | C++那些事
- Serialización ZeroCopy con Protobuf | C++那些事
- Diseño de una calculadora de pila en C++ | C++那些事