IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> Qt调用python -> 正文阅读

[Python知识库]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++程序一起打包没成功,不确定用pyinstaller的方式可不可行。

下面介绍携带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代码也可以直接写在程序中了,最后打包出来是二进制程序,会安全很多。

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2021-07-31 16:35:50  更:2021-07-31 16:35:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/4 4:38:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码