Qt调用python

Qt调用python,实际上就是c++调python,网上搜会出来很多,介绍得也比较全。这里做个记录

安装及使用

安装python,官网下载,按自己的需要是py2还是py3,是32位还是64位,这里就不多介绍了

安装完后找到安装目录,在pro文件链接py库

INCLUDEPATH += C:/Users/xx/AppData/Local/Programs/Python/Python39/include

LIBS += -LC:/Users/xx/AppData/Local/Programs/Python/Python39/libs -lpython39

由于是Qt上使用,简单封装成一个类,方便直接调用。

封装后的类如下:

#ifndef RDEXCUTEPYSCRIPT_H
#define RDEXCUTEPYSCRIPT_H

#undef slots
#include <Python.h>
#define slots Q_SLOTS
#include <QObject>
/**
* @className   RdExcutePyScript
* @brief       执行py类
* @author      song
* @date        2021-07-23
*/

class RdExcutePyScript
{
public:
    explicit RdExcutePyScript(const char *module);
    ~RdExcutePyScript();

    bool callPyFunc(const char *func, const QVariantList &args = QVariantList(), QVariant *backVar = nullptr);

private:
    PyObject *m_pModule = nullptr;

};

#endif // RDEXCUTEPYSCRIPT_H
#include "rdexcutepyscript.h"
#include <QVariant>
#include <QDebug>

RdExcutePyScript::RdExcutePyScript(const char *module)
{
    //设置py home 打包用
//    char homePath[] = "python_27_32";
//    Py_SetPythonHome(homePath);
    //进行初始化
    Py_Initialize();

    //设置.py文件的路径,不设置在程序生成目录下可以找到,当前设置./,在该文件下的.py文件就能够识别到
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");

    //如果初始化失败,返回
    if(!Py_IsInitialized()) {
        qDebug() << __FUNCTION__ << "song" << "py init fail";
        return;
    }

    //加载模块,模块名称为myModule,就是myModule.py文件
    m_pModule = PyImport_ImportModule(module);

}

RdExcutePyScript::~RdExcutePyScript()
{
    Py_Finalize();
}

bool RdExcutePyScript::callPyFunc(const char *func, const QVariantList &args, QVariant *backVar)
{
    if(m_pModule == nullptr) {
        qDebug() << __FUNCTION__ << "song" << "module is null";
        return false;
    }
    //加载函数greatFunc
    PyObject * pFuncHello = PyObject_GetAttrString(m_pModule, func);
    //如果失败则返回
    if(!pFuncHello) {
        qDebug() << __FUNCTION__ << "song" << "load function fail";
        return false;
    }

    PyObject* pArgs = PyTuple_New(args.size());
    for(int i = 0; i < args.size(); ++i) {
        QVariant arg = args.at(i);
        switch (arg.type()) {
        case QVariant::String:
        {
            QString str = arg.toString();
            std::string str2 = str.toStdString();
            const char *ch = str2.c_str();
            PyTuple_SetItem(pArgs, i, Py_BuildValue("s", ch));
        }
            break;
        case QVariant::Int:
            PyTuple_SetItem(pArgs, i, Py_BuildValue("i", arg.toInt()));
            break;
        case QVariant::Double:
            PyTuple_SetItem(pArgs, i, Py_BuildValue("d", arg.toDouble()));
            break;

        default:
            break;
        }
    }

    //调用函数
    auto pReturn = PyObject_CallObject(pFuncHello, pArgs);

    if(backVar) {
        switch (backVar->type()) {
        case QVariant::String:
        {
            char *s = nullptr;
            PyArg_Parse(pReturn, "s", &s);
            QString str(s);
            *backVar = QVariant::fromValue(str);
        }
            break;
        case QVariant::Int:
        {
            int nResult;
            PyArg_Parse(pReturn, "i", &nResult);
            *backVar = QVariant::fromValue(nResult);
        }
            break;
        case QVariant::Double:
        {
            double dResult;
            PyArg_Parse(pReturn, "d", &dResult);
            *backVar = QVariant::fromValue(dResult);
        }
            break;
        default:
            break;
        }
    }

    return pReturn != nullptr;
}

调用

#include <QCoreApplication>
#include <QDebug>
#include "rdexcutepyscript.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    RdExcutePyScript pyExcute("hello");
    bool rc = pyExcute.callPyFunc("hello");

    QVariant var = 0;
    QVariantList args = {1, 2};
    rc = pyExcute.callPyFunc("add", args, &var);
    qDebug() << __FUNCTION__ << "song" << var.toInt();

    QVariant var2 = 1.0;
    QVariantList args2 = {2.2, 3.3};
    rc = pyExcute.callPyFunc("add", args2, &var2);
    qDebug() << __FUNCTION__ << "song" << var2.toDouble();

    QVariant var3 = "";
    QVariantList args3 = {"hello ", "world"};
    rc = pyExcute.callPyFunc("add", args3, &var3);
    qDebug() << __FUNCTION__ << "song" << var3.toString();

    return a.exec();
}

运行

 py文件位置在工程目录下

py内容

# This Python file uses the following encoding: utf-8

# if __name__ == "__main__":
#     pass

def hello():
    print("Hello World")

def add(a, b):
    print("add test")
    return a+b

封装的类支持加载模块,即加载.py文件,并调用其中的函数,支持传参及返回值。传参和返回值使用Qt的通用类型QVariant进行实现。

不过感觉也不是很通用哈,没有实现传参传引用的效果,就是传参在函数内进行操作,函数外部的参数被修改,有需要的可以改造改造。传参和返回值目前只支持int、double、char *类型,根据需要再增加。

该方式调用链接的py库为release版本,对应的c++程序也需要是release

打包

最后是打包,由于python是解释性语言,正常来说需要有python的环境方能运行。一种打包方式是携带py的库一起打包,这样文件就会很大。目前网上常用的打包方式是pyinstaller,window下会打包成可执行文件exe,能够直接运行,打包出来也小了很多。试了一下纯py程序是能够用这种方式,c++调py用这种方式和c++程序一起打包没成功,根据调用原理来看,c++调用python是通过dll库调用.py文件中的函数,而pyinstall打包生成了平台可执行文件exe,c++没法调exe的内容,以我的理解来看只能带上py的库一起打包。

下面介绍携带py库一起打包的方式

由于我是Qt下调用,即打包Qt程序

1.先用windeployqt生成Qt程序需要的依赖,对熟悉Qt的来说这是基操了,这就不介绍了

2.在程序目录下创建py库文件夹,如python_39_64,把python安装目录下的DLLs和Lib复制到该文件夹下

3.把python的dll文件拷到程序目录下,把要执行的.py文件也拷到程序目录下,.pyc文件也可以

结构如下

4.最后还有关键的一步,程序里需要指定py home,这样才能找到对应的py库

auto pyPath = QCoreApplication::applicationDirPath() + "/python_39_64"
Py_SetPythonHome(reinterpret_cast<const wchar_t *>(pyPath.utf16()));

Py2可以是

char homePath[] = "python_27_32";
Py_SetPythonHome(homePath);

结语

以上是Qt /c++程序调用python的方式,缺点是打包后py的内容会暴露出来,使用.pyc文件应该能缓解一下这种情况,至少不是明文显示。当然更安全、更保密的做法可以是使用pyqt或者pyside2,使用python来写Qt程序,那所要调用的py代码也可以直接写在程序中了,最后打包出来是二进制程序,会安全很多。

  • 18
    点赞
  • 100
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
在这段代码中,是使用Qt框架调用Python的示例。首先,在主函数中初始化并配置Python环境,然后导入所需的Python模块和函数。在这个例子中,使用了Python.h头文件和Python的API函数来实现与Python的交互。在PyImport_ImportModule函数中,传入了要导入的Python文件的名称,这里是"temp"。然后使用PyObject_GetAttrString函数获取Python文件中定义的名为"Hello"的函数对象。最后使用PyObject_CallFunction函数调用该函数。整个过程中,还需要正确处理Python对象的引用计数,以避免内存泄漏。\[1\] 关于Qt调用Python的具体步骤,可以参考这段代码中的示例。需要注意的是,代码中的路径和模块名称需要根据实际情况进行修改。另外,还需要确保系统中已经安装了Python,并且Qt项目中已经正确配置了Python的相关路径\[2\]。 在使用Qt调用Python时,可以使用Python的C API来实现与Python的交互。这样可以在Qt项目中直接调用Python的函数和模块,实现更灵活的功能。同时,需要注意在使用Python对象时正确处理引用计数,以避免内存泄漏\[3\]。 #### 引用[.reference_title] - *1* [QT调用python文件](https://blog.csdn.net/weixin_47139559/article/details/123141479)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [QT调用py脚本(两种方法)](https://blog.csdn.net/New_codeline/article/details/123143138)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值