Incorporar / incluir Python.h em C ++ [Guia completo] (Python 3.9) (Windows) (Qt 5.15) [duplicado]

Dec 07 2020

Quando estava tentando incorporar um script Python em meu programa Qt C ++, tive vários problemas ao tentar incluir Python.h. Os seguintes recursos, eu gostaria de fornecer:

  • Inclui python.h
  • Execute Python Strings
  • Execute scripts Python
  • Execute scripts Python com argumentos
  • Também deve funcionar quando o Python não está instalado na máquina implantada

Por isso, pesquisei na Internet para tentar encontrar uma solução. E encontrei um monte de perguntas e blogs, mas não cobriu todos os meus problemas e ainda me levou várias horas e muita frustração. É por isso que tenho que escrever uma entrada StackOverflow com minha solução completa para que possa ajudar e acelerar todo o seu trabalho :)

Respostas

3 Olgidos Dec 07 2020 at 22:01

(Esta resposta e todos os seus exemplos de código funcionam também em um ambiente não-Qt. Apenas 2. e 4. são específicos do Qt)

  1. Baixe e instale o Python https://www.python.org/downloads/release
  2. Altere o arquivo .pro do seu projeto e adicione as seguintes linhas (edite para o caminho correto do Python):
INCLUDEPATH = "C:\Users\Public\AppData\Local\Programs\Python\Python39\include" 
LIBS += -L"C:\Users\Public\AppData\Local\Programs\Python\Python39\libs" -l"python39"
  1. Exemplo 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. Sempre que você #include <Python.h>, use o código a seguir. (Os Slots do Python irão entrar em conflito com os Slots Qt
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
  1. Após a compilação, adicione python3.dll, python39.dll, bem como as DLLs e as pastas Lib Python à sua pasta de compilação. Você pode encontrá-los no diretório raiz da instalação do Python. Isso permitirá que você execute o código c ++ incorporado mesmo quando o python não estiver instalado.

Com essas etapas, consegui colocar o python em execução no Qt com o compilador MinGW e MSVC de 64 bits. Apenas o MSVC em modo de depuração ainda tem um problema.

AVANÇAR:

Se você deseja passar argumentos para o script python, você precisa da seguinte função (pode ser fácil de copiar e colar em seu 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 função, chame-a assim (por exemplo em seu principal):

    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 com o script test.py na pasta de teste:

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)

você obtém a seguinte saída:

My command line args are Progamm and Hello