QT(6.5) cmake构建C++编程,调用python (已更新:2024.3.23晚)

news/2024/7/23 21:09:16 标签: qt, c++, python

一、注意事项

  1. explicit
    c++中,一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数),承担了两个角色,构造器、类型转换操作符,
    c++提供关键字explicit,阻止转换构造函数进行的隐式转换的发生,声明explicit的构造函数不能在隐式转换中使用。
  2. c++ 函数前面和后面 使用const 的作用
    前面使用const 表示返回值为const;
    后面加 const表示函数不可以修改class的成员;
    const成员函数可以被非const对象和const对象调用;
    非const成员函数只能被非const对象调用;
  3. 类外补充函数的定义要加作用域限定符::

二、重要知识:cmake
在QT中选择cmake方式构建c++项目,最好提前了解cmake相关知识,以方便理解如何导入外部库,推荐学习视频链接:B站:爱编程的大丙
重要细节:静态库的链接要放在add_executable之前

三、c++代码调用python步骤

  1. 设置python配置
    CMakeList.txt文件中输入python文件的相关信息:头文件夹路径、库文件夹路径、需要连接的库文件名称(有没有.lib后缀都可)
include_directories(C:/programming/anaconda3/envs/pytorch/include)
link_directories(C:/programming/anaconda3/envs/pytorch/libs)
link_libraries(python3)
link_libraries(python38)

在这里插入图片描述
2. c++代码(.cpp)中调用python注:下面代码中功函数invokePython的调用只可执行一次,再次调用程序会崩溃

#include "My_Functions.h"
#include <QDir>
#include <Python.h>

My_Functions::My_Functions(QObject *parent) : QObject(parent){}
My_Functions:: ~My_Functions(){}

bool My_Functions :: invokePython(){
    QDir dir;
    const char* pythonFilePath = (dir.currentPath().append("/").append(dir.currentPath().split("/").last().split("-")[1])).toUtf8();
    Py_SetPythonHome(L"C:/programming/anaconda3/envs/pytorch");
    //调用前必须初始化python解释器
    Py_Initialize();
    if(!Py_IsInitialized()){qDebug()<<"初始化失败"; return 0;}

    // 将路径转换为Python对象
    PyObject *py_path_str = PyUnicode_FromWideChar(Py_DecodeLocale(pythonFilePath, NULL), -1);
    // 加载 python 脚本
    // 获取sys模块以进行项目.py文件的搜索
    PyObject *sys_module = PyImport_ImportModule("sys");

    // 获取sys.path
    PyObject *sys_path = PyObject_GetAttrString(sys_module, "path");
    if (!PyList_Check(sys_path)) {
        // sys.path不是列表,错误处理
        qDebug()<<"获取py搜索路径失败" ;

        // 释放python所用内存
        Py_Finalize();
        return 0;
    } else {
        // 将自定义路径添加到sys.path
        int appended = PyList_Append(sys_path, py_path_str);
        if (appended == -1) {
            // 错误处理
            qDebug()<<"添加py搜索路径失败" ;

            // 释放python所用内存
            Py_Finalize();
            return 0;
        }
    }


    PyObject *pModule = PyImport_ImportModule("onnxUse");
    if (pModule == NULL) {
        // 模块导入失败,处理错误
        qDebug() << "脚本加载失败";

        // 释放python所用内存
        Py_Finalize();
        return 0;
    } else {
        qDebug() << "脚本加载成功";
    }
    // 创建函数指针
    PyObject* pFunc = PyObject_GetAttrString(pModule, "detect_images");  // 方法名称
    if (pFunc == NULL) {
        // 函数导入失败,处理错误
        qDebug() << "函数创建失败";

        // 释放python所用内存
        Py_Finalize();
        return 0;
    }else {
        qDebug() << "函数创建成功";
    }

    // 调用有参函数
    // 创建函数参数
    // s 将C字符串转换成Python对象,如果C字符串为空,返回NONE
    // z: 类似于 s,但允许转换为 NULL(Python 的 None)
    // c 将C类型的char转换成长度为1的Python字符串对象
    // b: C unsigned char,将布尔值转换为 0 或 1
    // i 将一个C类型的int转换成Python int对象
    // k: C unsigned long,转换为无符号长整数
    // l 将C类型的long转换成Pyhon中的int对象
    // f 将C类型的float转换成python中的浮点型对象
    // d 将C类型的double转换成python中的浮点型对象
    // O 通用对象引用,接收任意 Python 对象而不转换
    // O!: 类型对象和转换标志,用于接收特定类型的 Python 对象
    // O&: 自定义回调函数,用于自定义对象转换
    // (ii):两个 C 整型变量构成的元组或列表
    // [ii]:两个 C 整型变量构成的列表
    // {ss}:键值对都是 C 字符串的字典
    // #:s, #i, #d 等:带有长度指示的字符串、整数或浮点数
    // n: 接收 None,检查参数是否为 None

    // PyObject* args = Py_BuildValue("(i,s)", 110, "hello");  // 参数为整数 110 和字符串 "hello"
    // PyObject *result  = PyObject_CallObject(pFunc, args);

    // 调用无参函数
    PyObject *result  = PyObject_CallObject(pFunc, NULL);

    // 检查并处理有参函数调用的返回结果
    if (result  == NULL) {
        // 处理错误
        qDebug() << "函数调用失败";

        // 释放python所用内存
        Py_Finalize();
        return 0;
    } else {
        // 使用返回值
        qDebug() << "函数调用成功";

        // const char *result_str;
        // if (!PyArg_Parse(result, "s", &result_str)) {
        //     // 错误处理:无法将Python对象转换为字符串
        //     qDebug() << "函数返回值处理失败";

        //     // 释放python所用内存
        //     Py_Finalize();
        //     return 0;
        // } else {
        //     // 使用result_str
        // }
    }

    // 释放引用计数
    Py_DECREF(result);
    // // 释放参数元组
    // Py_DECREF(args);
    // 释放函数指针
    Py_DECREF(pFunc);
    // 不再需要模块时,减少引用计数
    Py_DECREF(pModule);
    // 释放python所用内存
    Py_Finalize();
    qDebug()<<"调用完成";
    return false;
}
  1. 局部多次调用python脚本
    改造 invokePython 函数
bool My_Functions :: invokePython(){
    PyGILState_STATE gil_state;  // 用以保存获取的Global Interpreter Lock (GIL)
    gil_state = PyGILState_Ensure();  // 获取GIL,只有拥有GIL的线程才可以执行python代码
    PyObject *pModule = PyImport_ImportModule("onnxUse");
    if (pModule == NULL) {
        // 模块导入失败,处理错误
        qDebug() << "脚本加载失败";
        return 0;
    } else {
        qDebug() << "脚本加载成功";
    }
    // 创建函数指针
    PyObject* pFunc = PyObject_GetAttrString(pModule, "detect_images");  // 方法名称
    if (pFunc == NULL) {
        // 函数导入失败,处理错误
        qDebug() << "函数创建失败";
        PyErr_Print();
        return 0;
    }else {
        qDebug() << "函数创建成功";
    }

    // 调用无参函数
    PyObject *result  = PyObject_CallObject(pFunc, NULL);

    // 检查并处理有参函数调用的返回结果
    if (result  == NULL) {
        // 处理错误
        qDebug() << "函数调用失败";

        return 0;
    } else {
        // 使用返回值
        qDebug() << "函数调用成功";

        // const char *result_str;
        // if (!PyArg_Parse(result, "s", &result_str)) {
        //     // 错误处理:无法将Python对象转换为字符串
        //     qDebug() << "函数返回值处理失败";

        //     // 释放python所用内存
        //     Py_Finalize();
        //     return 0;
        // } else {
        //     // 使用result_str
        // }
    }
    // 释放引用计数
    Py_DECREF(result);
    // // 释放参数元组
    // Py_DECREF(args);
    // 释放函数指针
    Py_DECREF(pFunc);
    // 不再需要模块时,减少引用计数
    Py_DECREF(pModule);
    PyGILState_Release(gil_state);  // 释放GIL,释放前确保获取到了GIL,同时最好主动释放各计数,以防发生内存泄漏
    return false;
}

同时不要忘记初始化python解释器(注:整个程序只可初始化一次,结束程序前再释放,否则再次初始化程序会崩溃),下面是改造后的初始化函数
头文件:

#ifndef INVOKE_PYTHON_INIT_H
#define INVOKE_PYTHON_INIT_H
#include <QObject>
#include <Python.h>

class Invoke_Python_Init
{
public:
    Invoke_Python_Init();
    ~Invoke_Python_Init();
private:
    QString pythonDirectoryPath;
    bool init();
    void initPythonDirectoryPath();
    bool pythonDirectoryIsInit = false;
    bool pythonIsInited = false;
};

#endif // INVOKE_PYTHON_INIT_H

源码文件:

#include "invoke_python_init.h"
#include <qDebug>
#include <QDir>

Invoke_Python_Init :: Invoke_Python_Init() {init();}
Invoke_Python_Init :: ~Invoke_Python_Init() {
    // 释放python所用内存
    Py_Finalize();
    qDebug()<<"释放python解释器完成";
}

bool Invoke_Python_Init :: init() {
    initPythonDirectoryPath();
    if (!pythonDirectoryIsInit) {qDebug()<<"路径初始化失败" ; return 0;}
    Py_SetPythonHome(L"C:/programming/anaconda3/envs/pytorch");
    //调用前必须初始化python解释器
    Py_Initialize();
    if(!Py_IsInitialized()){qDebug()<<"python解释器初始化失败"; return 0;}

    // 将路径转换为Python对象
    PyObject *py_path_str = PyUnicode_FromWideChar(Py_DecodeLocale(pythonDirectoryPath.toLocal8Bit().constData(), NULL), -1);
    // 加载 python 脚本
    // 获取sys模块以进行项目.py文件的搜索
    PyObject *sys_module = PyImport_ImportModule("sys");

    // 获取sys.path
    PyObject *sys_path = PyObject_GetAttrString(sys_module, "path");
    if (!PyList_Check(sys_path)) {
        // sys.path不是列表,错误处理
        qDebug()<<"获取py搜索路径失败\n" ;
        return 0;
    } else {
        // 将自定义路径添加到sys.path
        int appended = PyList_Append(sys_path, py_path_str);
        if (appended == -1) {
            // 错误处理
            qDebug()<<"添加py搜索路径失败" ;
            return 0;
        }

        // 将sys.path转换为QStringList
        QStringList pythonPathList;
        // 遍历sys.path列表
        for (Py_ssize_t i = 0; i < PyList_Size(sys_path); ++i) {
            PyObject *path_item = PyList_GetItem(sys_path, i);
            // 将路径元素转换为QString
            QString path_str = QString::fromUtf8(PyUnicode_AsUTF8(path_item));
            // 添加到QStringList
            pythonPathList.append(path_str);
            // 减少引用计数
            Py_DECREF(path_item);
        }
        // 输出所有搜索路径到QDebug
        foreach (const QString &path, pythonPathList) {
            qDebug() << path<< "\n";
        }
    }
    PyEval_ReleaseThread(PyThreadState_Get());
    pythonIsInited = true;
    qDebug("Python解释器初始化成功");
    return true;
}
void Invoke_Python_Init :: initPythonDirectoryPath(){
    QDir dir;
    // 构建新的路径
    QString Path = dir.currentPath().append("/").append(dir.currentPath().split("/").last().split("-")[1]);
    // 将QString赋值给pythonFilePath
    pythonDirectoryPath = Path;
    pythonDirectoryIsInit = true;
}

在认为合适的地方初始化 Invoke_Python_Init 类,初始化完成后便可重复调用 invokePython 函数,即重复调用 python 脚本。

未完待续


http://www.niftyadmin.cn/n/5450295.html

相关文章

常用GPT网站综述:探索人工智能的前沿技术平台

常用GPT网站综述&#xff1a;探索人工智能的前沿技术平台 目录 常用GPT网站综述&#xff1a;探索人工智能的前沿技术平台 一、引言 二、OpenAI ChatGPT 三、Google AI Platform 四、Microsoft Azure Cognitive Services 五、Amazon Web Services (AWS) 六、IBM Watson 七…

Rust 实战练习 - 5. 多线程,多进程,协程

目标&#xff1a; 多进程多线程Rust的协程 多进程 use std::process::{Command, Stdio};fn main() {println!("call new exe in process:");// netstat -ntlp // 耗时很短&#xff0c;所以看不出效果// netstat -p // 耗时很长&#xff0c;如果可以异步输出&…

代码随想录day30(1)二叉树:把二叉搜索树转换为累加树(leetcode538)

题目要求&#xff1a;给出二叉搜索树的根节点&#xff0c;该树的节点值各不相同&#xff0c;请你将其转换为累加树&#xff08;Greater Sum Tree&#xff09;&#xff0c;使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。 思路&#xff1a;对于二叉搜索树来说…

web前端之罗盘时钟、不一样的补零方式、LED字体、padStart

MENU 效果图htmlJavaScriptstyle 效果图 html <div class"clock"><div class"second-box"></div><div class"minute-box"></div><div class"hour-box"></div><div class"day-box&…

2024了,华为HCIP认证还值得考吗?

华为HCIP(Huawei Certified ICT Professional)认证作为华为认证体系中的高级认证之一&#xff0c;更是被众多IT人士视为职业晋升的“金钥匙”。 那么&#xff0c;华为HCIP认证究竟值不值得考&#xff1f;它又能为持证者带来哪些实际好处呢&#xff1f;接下来&#xff0c;我们将…

指针知识大礼包,让你的编程之路更顺畅(二)

1. 数组名的理解 2. 使⽤指针访问数组 3. ⼀维数组传参的本质 4. ⼆级指针 5. 指针数组 6. 指针数组模拟⼆维数 正文开始&#xff1a; 1. 数组名的理解 在上⼀个章节我们在使⽤指针访问数组的内容时&#xff0c;有这样的代码&#xff1a; int arr[10] {1,2,3,4,5,6,7,…

HDFS集群环境配置

HDFS集群环境配置 环境如下三台服务器&#xff1a; 192.168.32.101 node1192.168.32.102 node2192.168.32.103 node3 一、Hadoop安装包下载​​​​​​​ 点此官网下载​​​​​​​ 二、Hadoop HDFS的角色包含&#xff1a; NameNode&#xff0c;主节点管理者DataNode&am…

ssm005基于SSM框架的购物商城系统+jsp

购物商城系统的设计与实现 摘 要 网络技术和计算机技术发展至今&#xff0c;已经拥有了深厚的理论基础&#xff0c;并在现实中进行了充分运用&#xff0c;尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代&#xff0c;所以对于信息的宣传和管理就…