Insertar / incluir Python.h en C ++ [Guía completa] (Python 3.9) (Windows) (Qt 5.15) [duplicar]

Dec 07 2020

Cuando intentaba incrustar un script de Python en mi programa Qt C ++, me encontré con varios problemas al intentar incluir Python.h. Las siguientes características, me gustaría proporcionar:

  • Incluir python.h
  • Ejecutar cadenas de Python
  • Ejecutar secuencias de comandos de Python
  • Ejecutar secuencias de comandos de Python con argumentos
  • También debería funcionar cuando Python no está instalado en la máquina implementada

Por lo tanto, busqué en Internet para tratar de encontrar una solución. Y encontré muchas preguntas y blogs, pero no los cubrí todos mis problemas y todavía me tomó varias horas y mucha frustración. Es por eso que tengo que escribir una entrada de StackOverflow con mi solución completa para que pueda ayudar y acelerar todo su trabajo :)

Respuestas

3 Olgidos Dec 07 2020 at 22:01

(Esta respuesta y todos sus ejemplos de código también funcionan en un entorno que no es Qt. Solo 2. y 4. son específicos de Qt)

  1. Descarga e instala Python https://www.python.org/downloads/release
  2. Modifique el archivo .pro de su proyecto y agregue las siguientes líneas (edite para su ruta de Python correcta):
INCLUDEPATH = "C:\Users\Public\AppData\Local\Programs\Python\Python39\include" 
LIBS += -L"C:\Users\Public\AppData\Local\Programs\Python\Python39\libs" -l"python39"
  1. Ejemplo de código main.cpp:
#include <QCoreApplication>

#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")

/*!
 * \brief runPy can execut a Python string
 * \param string (Python code)
 */
static void runPy(const char* string){
    Py_Initialize();
    PyRun_SimpleString(string);
    Py_Finalize();
}

/*!
 * \brief runPyScript executs a Python script
 * \param file (the path of the script)
 */
static void runPyScript(const char* file){
    FILE* fp;
    Py_Initialize();
    fp = _Py_fopen(file, "r");
    PyRun_SimpleFile(fp, file);
    Py_Finalize();
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    runPy("from time import time,ctime\n"
      "print('Today is', ctime(time()))\n");

    //uncomment the following line to run a script
    //runPyScript("test/decode.py");

    return a.exec();
}
  1. Siempre que #incluya <Python.h> use el siguiente código en su lugar. (Las ranuras de Python entrarán en conflicto con las ranuras de Qt
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
  1. Después de compilar, agregue python3.dll, python39.dll, así como las carpetas DLL y Lib Python a su carpeta de compilación. Puede encontrarlos en el directorio raíz de su instalación de Python. Esto le permitirá ejecutar el código C ++ incrustado incluso cuando Python no esté instalado.

Con estos pasos, pude ejecutar Python en Qt con el compilador MinGW y MSVC de 64 bits. Solo el MSVC en modo de depuración siguió siendo un problema.

MÁS:

Si desea pasar argumentos al script de Python, necesita la siguiente función (se puede copiar y pegar fácilmente en su código):

/*!
 * \brief runPyScriptArgs executs a Python script and passes arguments
 * \param file (the path of the script)
 * \param argc amount of arguments
 * \param argv array of arguments with size of argc
 */
static void runPyScriptArgs(const char* file, int argc, char *argv[]){
    FILE* fp;
    wchar_t** wargv = new wchar_t*[argc];
    for(int i = 0; i < argc; i++)
    {
        wargv[i] = Py_DecodeLocale(argv[i], nullptr);
        if(wargv[i] == nullptr)
        {
            return;
        }
    }
    Py_SetProgramName(wargv[0]);

    Py_Initialize();
    PySys_SetArgv(argc, wargv);
    fp = _Py_fopen(file, "r");
    PyRun_SimpleFile(fp, file);
    Py_Finalize();

    for(int i = 0; i < argc; i++)
    {
        PyMem_RawFree(wargv[i]);
        wargv[i] = nullptr;
    }

    delete[] wargv;
    wargv = nullptr;
}

Para usar esta función, llámala así (por ejemplo en tu main):

    int py_argc = 2;
    char* py_argv[py_argc];

    py_argv[0] = "Progamm";
    py_argv[1] = "Hello";

    runPyScriptArgs("test/test.py", py_argc, py_argv);

Junto con el script test.py en la carpeta de prueba:

import sys

if len(sys.argv) != 2:
  sys.exit("Not enough args")

ca_one = str(sys.argv[0])
ca_two = str(sys.argv[1])
print ("My command line args are " + ca_one + " and " + ca_two)

obtienes el siguiente resultado:

My command line args are Progamm and Hello