¿Cuál sería la forma más rápida de construir un enlace de Python a una biblioteca C o C ++?
(Estoy usando Windows si esto es importante).
Deberías echar un vistazo a Boost.Python . Aquí está la breve introducción tomada de su sitio web:
Boost Python Library es un marco para la interfaz de Python y C ++. Le permite exponer rápida y sin problemas las funciones y objetos de las clases de C ++ a Python, y viceversa, sin utilizar herramientas especiales, solo su compilador de C ++. Está diseñado para envolver las interfaces de C ++ de manera no intrusiva, por lo que no debería tener que cambiar el código de C ++ para envolverlo, lo que hace que Boost.Python sea ideal para exponer bibliotecas de terceros a Python. El uso de la biblioteca de técnicas avanzadas de metaprogramación simplifica su sintaxis para los usuarios, de modo que el código de ajuste adopta la apariencia de un tipo de lenguaje de definición de interfaz declarativa (IDL).
El módulo ctypes es parte de la biblioteca estándar y, por lo tanto, es más estable y está más disponible que Swig , lo que siempre me causó problemas .
Con ctypes, debe satisfacer cualquier dependencia del tiempo de compilación en python, y su enlace funcionará en cualquier python que tenga ctypes, no solo en el que se compiló.
Suponga que tiene una clase de ejemplo C ++ simple con la que desea hablar en un archivo llamado foo.cpp:
Dado que los ctypes solo pueden comunicarse con las funciones de C, debe proporcionar a aquellos que las declaran como "C" externas
Luego debes compilar esto en una biblioteca compartida
Y finalmente tienes que escribir tu envoltorio de python (por ejemplo, en fooWrapper.py)
Una vez que tenga eso, puede llamarlo así
fuente
extern "C" { __declspec(dllexport) Foo* Foo_new(){ return new Foo(); } __declspec(dllexport) void Foo_bar(Foo* foo){ foo->bar(); } }
Foo_delete
función y llamándola desde un destructor de python o envolviendo el objeto en un recurso .La forma más rápida de hacer esto es usar SWIG .
Ejemplo del tutorial SWIG :
Archivo de interfaz:
Construyendo un módulo Python en Unix:
Uso:
Tenga en cuenta que debe tener python-dev. Además, en algunos sistemas, los archivos de encabezado de Python estarán en /usr/include/python2.7 según la forma en que lo haya instalado.
Del tutorial:
fuente
Comencé mi viaje en el enlace Python <-> C ++ desde esta página, con el objetivo de vincular tipos de datos de alto nivel (vectores STL multidimensionales con listas de Python) :-)
Después de haber probado las soluciones basadas en ctypes y boost.python (y no ser un ingeniero de software), las he encontrado complejas cuando se requiere un enlace de tipos de datos de alto nivel, mientras que he encontrado SWIG es mucho más simple para tales casos.
Este ejemplo utiliza, por lo tanto, SWIG, y se ha probado en Linux (pero SWIG está disponible y también se usa ampliamente en Windows).
El objetivo es poner a disposición de Python una función C ++ que tome una matriz en forma de un vector STL 2D y devuelva un promedio de cada fila (como un vector STD 1D).
El código en C ++ ("code.cpp") es el siguiente:
El encabezado equivalente ("code.h") es:
Primero compilamos el código C ++ para crear un archivo objeto:
Luego definimos un archivo de definición de interfaz SWIG ("code.i") para nuestras funciones C ++.
Usando SWIG, generamos un código fuente de interfaz C ++ a partir del archivo de definición de interfaz SWIG.
Finalmente compilamos el archivo fuente de la interfaz C ++ generada y enlazamos todo para generar una biblioteca compartida que Python puede importar directamente (el "_" importa):
Ahora podemos usar la función en scripts de Python:
fuente
También existe
pybind11
, que es como una versión ligera de Boost.Python y compatible con todos los compiladores de C ++ modernos:https://pybind11.readthedocs.io/en/latest/
fuente
Pytorch
pytorch.org/tutorials/advanced/cpp_extension.html También funciona completamente enVS Community
WindowsEcha un vistazo a pyrex o Cython . Son lenguajes similares a Python para la interfaz entre C / C ++ y Python.
fuente
Para C ++ moderno, use cppyy: http://cppyy.readthedocs.io/en/latest/
Está basado en Cling, el intérprete de C ++ para Clang / LLVM. Los enlaces están en tiempo de ejecución y no es necesario un lenguaje intermedio adicional. Gracias a Clang, es compatible con C ++ 17.
Instalarlo usando pip:
Para proyectos pequeños, simplemente cargue la biblioteca relevante y los encabezados que le interesen. Por ejemplo, tome el código del ejemplo ctypes de este hilo, pero divídalo en secciones de encabezado y código:
Compilarlo:
y úsalo:
Los proyectos grandes son compatibles con la carga automática de información de reflexión preparada y los fragmentos cmake para crearlos, de modo que los usuarios de los paquetes instalados puedan simplemente ejecutar:
Gracias a LLVM, son posibles funciones avanzadas, como la creación de instancias de plantilla automática. Para continuar el ejemplo:
Nota: soy el autor de cppyy.
fuente
swig
,ctypes
oboost.python
. En lugar de tener que escribir código para que Python funcione con su código C ++ ... Python hace el trabajo duro para descubrir C ++. Suponiendo que realmente funcione.Este documento, que afirma que Python es todo lo que un científico necesita , básicamente dice: Primero prototipo de todo en Python. Luego, cuando necesite acelerar una parte, use SWIG y traduzca esta parte a C.
fuente
Nunca lo he usado, pero he escuchado cosas buenas sobre los ctypes . Si está intentando usarlo con C ++, asegúrese de evadir el cambio de nombre a través de
extern "C"
. Gracias por el comentario, Florian Bösch.fuente
Creo que cffi para python puede ser una opción.
http://cffi.readthedocs.org/en/release-0.7/
fuente
La pregunta es cómo llamar a una función C desde Python, si entendí correctamente. Entonces la mejor apuesta son los Ctypes (por cierto, portátiles en todas las variantes de Python).
Para obtener una guía detallada, puede consultar el artículo de mi blog .
fuente
Uno de los documentos oficiales de Python contiene detalles sobre cómo extender Python usando C / C ++ . Incluso sin el uso de SWIG , es bastante sencillo y funciona perfectamente bien en Windows.
fuente
Cython es definitivamente el camino a seguir, a menos que anticipe escribir envoltorios Java, en cuyo caso SWIG puede ser preferible.
Recomiendo usar la
runcython
utilidad de línea de comandos, hace que el proceso de usar Cython sea extremadamente fácil. Si necesita pasar datos estructurados a C ++, eche un vistazo a la biblioteca de protobuf de Google, es muy conveniente.Aquí hay algunos ejemplos mínimos que hice que usa ambas herramientas:
https://github.com/nicodjimenez/python2cpp
Espero que pueda ser un punto de partida útil.
fuente
Primero debes decidir cuál es tu propósito particular. La documentación oficial de Python sobre la extensión e incrustación del intérprete de Python se mencionó anteriormente, puedo agregar una buena descripción general de las extensiones binarias . Los casos de uso se pueden dividir en 3 categorías:
Para dar una perspectiva más amplia a otros interesados y dado que su pregunta inicial es un poco vaga ("a una biblioteca C o C ++"), creo que esta información puede ser interesante para usted. En el enlace de arriba puede leer las desventajas de usar extensiones binarias y sus alternativas.
Además de las otras respuestas sugeridas, si desea un módulo acelerador, puede probar Numba . Funciona "generando código de máquina optimizado utilizando la infraestructura del compilador LLVM en el momento de la importación, el tiempo de ejecución o de forma estática (utilizando la herramienta pycc incluida)".
fuente
Me encanta cppyy, hace que sea muy fácil extender Python con código C ++, aumentando drásticamente el rendimiento cuando sea necesario.
Es poderoso y francamente muy simple de usar,
Aquí es un ejemplo de cómo puede crear una matriz numpy y pasarla a una función miembro de la clase en C ++.
cppyy_test.py
Buffer.h
También puede crear un módulo Python muy fácilmente (con CMake), de esta manera evitará recompilar el código C ++ todo el tiempo.
fuente
Ejemplo ejecutable mínimo de pybind11
pybind11 se mencionó anteriormente en https://stackoverflow.com/a/38542539/895245 pero me gustaría dar aquí un ejemplo de uso concreto y alguna discusión adicional sobre la implementación.
En general, recomiendo pybind11 porque es realmente fácil de usar: solo incluye un encabezado y luego pybind11 usa la magia de la plantilla para inspeccionar la clase de C ++ que desea exponer a Python y lo hace de forma transparente.
La desventaja de esta plantilla mágica es que ralentiza la compilación inmediatamente agregando unos segundos a cualquier archivo que use pybind11, vea por ejemplo la investigación realizada sobre este tema . PyTorch está de acuerdo .
Aquí hay un ejemplo ejecutable mínimo para darle una idea de lo increíble que es pybind11:
class_test.cpp
class_test_main.py
Compilar y ejecutar:
¡Este ejemplo muestra cómo pybind11 le permite exponer sin esfuerzo la
ClassTest
clase C ++ a Python! La compilación produce un archivo llamadoclass_test.cpython-36m-x86_64-linux-gnu.so
queclass_test_main.py
se selecciona automáticamente como el punto de definición paraclass_test
módulo definido de forma nativa.Tal vez la comprensión de lo increíble que esto es solo se hunde si intenta hacer lo mismo a mano con la API nativa de Python, vea, por ejemplo, este ejemplo de hacer eso, que tiene aproximadamente 10 veces más código: https://github.com /cirosantilli/python-cheat/blob/4f676f62e87810582ad53b2fb426b74eae52aad5/py_from_c/pure.c En ese ejemplo, puede ver cómo el código C debe definir dolorosa y explícitamente la clase de Python poco a poco con toda la información que contiene (miembros, métodos, más metadatos ...). Ver también:
pybind11 afirma ser similar al
Boost.Python
mencionado en https://stackoverflow.com/a/145436/895245 pero más mínimo porque se libera de la hinchazón de estar dentro del proyecto Boost:pybind11 también es la única alternativa no nativa destacada por la documentación de enlace actual de Microsoft Python C en: https://docs.microsoft.com/en-us/visualstudio/python/working-with-c-cpp-python-in- visual-studio? view = vs-2019 ( archivo ).
Probado en Ubuntu 18.04, pybind11 2.0.1, Python 3.6.8, GCC 7.4.0.
fuente