en Tutoriales, Windows

Usando Python en aplicaciones C++

Con esta serie de tutoriales vamos a explorar el mundo de la mezcla the lenguajes en una misma aplicación o su interacción en caso de tener dos aplicaciones diferentes. Trataremos de resolver los problemas más habituales que nos podemos encontrar en este tipo de soluciones.

Introducción
Mejoras de rendimiento

Nuestro primer experimento será mezclar Python y C++. Inicializaremos un interprete de python dentro de una aplicación C++ e importaremos un módulo de python para ejecutar alguna de sus funciones.

En vez de utilizar directamente CPython vamos a utilizar una librería pybind11 para facilitar los bindings y simplificar el proceso.

cpp_python_app

Pybind11 es una librería header-only, solo necesitaremos copiar su carpeta include de su repositorio de GitHub y ponerla dentro de nuestro proyecto c++

pybind11_includes

Tendremos que añadir esta carpeta include a nuestros parámetros de compilación c++. En Visual Studio podemos encontrar estas opción en Project > Properties > VC++ Directories > Include Directories. Tendremos que añadir los de pybind11 y la carpeta de la instalación de python en la que se encuentra la cabecera Python.h que usaremos para nuestro interprete

vc_python_include

Podemos aprovechar y añadir ya también la ruta a la librería de python que se usará en la fase de enlace de librerías en Project > Properties > VC++ Directories > Library Directories

vc_python_libs

Ahora añadiremos nuestro código C++ de ejemplo

#include <iostream>

#include <pybind11/embed.h>

namespace py = pybind11;
int main()
{
	{
		py::scoped_interpreter guard{};
		py::module_ math_module = py::module_::import("math");
		py::object result = math_module.attr("cos")(0.5);

		std::cout << "C++ cout" << std::endl;
		std::cout << py::cast<float>(result) << std::endl;

		py::print("Python print");
		py::print(result);
	}
	return 0;
}

En las primeras líneas inicializamos el intérprete utilizando un scoped guard, cuando salga del scope el intérprete se destruirá. Esta gestión tambien la podríamos hacer nosotros mismos, por ejemplo, iniciar el intéprete en una parte y finalizarlo en otra parte del código. La única cosa importante a tener en cuenta es que todo objeto de python que creamos en el intérprete debe ser liberado antes de la finalización de dicho intérprete, no podemos quedarnos con objetos de python o referencias fuera del tiempo de vida del intérprete.

To import a module we can use pybind11::module_::import with the name of the module, this module is searched using the sys.path of the current interpreter. To access to the function we can use the module.attr with the name of the function and their function parameters after the call

Para utilizar objetos de python con funciones de c++ necesitamos aplicar un cast a un tipo compatible, en nuestro ejemplo hacemos un cast del objeto result obtenido en la salida de la función math.cos a un float para poder imprimir el valor mediando un std::cout.

También podemos utilizar el objeto directamente con funciones builtin de python, como por ejemplo print, para mostrar el contenido de result en la salida por consola

cpp_python_output

Y con esto ya tenemos una aplicación c++ que puede utilizar módulos de python en tiempo de ejecución. Una manera muy buena de poder hacer cambios sin la necesidad de recompilar la aplicación principal!

Ayudanos con este blog!

El último año he estado dedicando cada vez más tiempo a la creación de tutoriales, en su mayoria sobre desarrollo de videojuegos. Si crees que estos posts te han ayudado de alguna manera o incluso inspirado, por favor considera ayudarnos a mantener este blog con alguna de estas opciones. Gracias por hacerlo posible!

Escribe un comentario

Comentario