En un tutorial anterior vimos como utilizar código python en una aplicacion c++, hoy veremos el otro lado, como usar código c++ en scripts de python
Introducción: Python en C++
Mejoras de rendimiento
Usando código C++ en Python
Para poder cargar y utilizar código c++ en un módulo de python tendremos que empaquetarlo en una biblioteca compartida. En Windows se suelen llamar Bibliotecas de enlace dinámico (DLL), para utilizar estas bibliotecas en otra plataforma necesitamos generar una biblioteca compartida con extensión .so
Cuando creamos el proyecto en Visual Studio tendremos que elegir en la lista de plantillas el tipo dynamic library.
Una cosa que tendremos que cambiar es la extensión de nuestra biblioteca c++ de .dll a .pyd. En Visual Studio tenemos la opción en Project > Properties > Advanced > Target File Extension
En Windows, python no será capaz de importar la biblioteca si tiene una extensión diferente a .pyd.
La configuración del proyecto en cuanto a includes y enlace de las bibliotecas necesarias para utilizar pybind11 se pueden encontrar en el tutorial anterior usando python into c++.
Para definir el módulo python que será exportado por la biblioteca tenemos que usar la macro PYBIND11_MODULE(nombre_modulo, variable_modulo). Solo un módulo puede definirse por fichero .cpp o biblioteca, el nombre_modulo debe ser el mismo que el nombre de la biblioteca.
Para nuestro ejemplo vamos a definir una función para calcular el coseno multiple veces, una pequeña muestra para comparar la diferencia de tiempos entre python y c++ ejecutando un código similar.
#include <math.h> #include <pybind11/pybind11.h> namespace py = pybind11; double icos(double num, int iterations) { double value = 0; for (int i = 0; i < iterations; ++i) { value = std::cos(num); } return value; } PYBIND11_MODULE(cppython3, m) { m.def("icos", &icos, "Calculates cosine multiple times"); }
Para enlazar nuestra función icos dentro del módulo tenemos que definir la funcion en la macro PYBIND11_MODULE y usar la variable_modulo para enlazar el nombre de la función python y el puntero a la función c++, una breve descripción se puede añadir tambien en este punto.
Después de hacer la Build del proyecto podemos encontrar el binario de la biblioteca .pyd en la carpeta de salida del proyecto.
Para poder importar el módulo c++ tendremos que poner el .pyd en la misma carpeta que el script de python que lo utilize, o añadir la ruta a su carpeta en el sys.path de python, o utilizar la variable de entorno PYTHONPATH.
import cppython3 cpp_res = cppython3.icos(18, 1000000)
Después solo necesitamos importar la biblioteda utilizando su nombre y mediante este invocar la función como si de un módulo de python se tratara.
Añadimos un test de rendimiento para comprobar la diferencia de tiempos entre ejecutar la función con código python y c++.
from time import time from math import cos import cppython3 num = 18 iterations = 1000000 cpp_start = time() cpp_res = cppython3.icos(num, iterations) cpp_end = time() py_start = time() py_res = 0 for _ in range(iterations): py_res = cos(num) py_end = time() print(f" cpp time: {cpp_end-cpp_start}") print(f"python time: {py_end-py_start}") print(f" cpp result: {cpp_res}") print(f"python result: {py_res}")
La salida nos muestra como el módulo c++ tiene mejor rendimiento que la versión de la función de python, algo esperado por múltiples razones como la gestión de memoria, manejadores internos de punteros para el Global Interpreter Lock, la falta de tipado estático…
Con esto hemos visto como implementar nuestros módulos de python con c++, como importar y como utilizar después sus funciones en nuestros scripts de python. Es una manera interesante para mejorar el rendimiento de ciertas funciones o incluso módulos completos de python!
Te puede interesar:
Ayudanos con este blog!
En el último año hemos 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!