德才兼备 知行合一

Qt调用Python函数

Posted on By Dason Mo

实验室做项目时遇到的工程问题,记录下来以备查用。Python底层是由C编写的,二者间的相互调用是常见的操作。调用基本可分为extension和embedding两种,前者是Python程序为了提高运行速度加入C的扩展模块,后者则是C程序调用Python函数以利用其丰富的库函数和简洁的代码。两种方法都在官网上有详细的介绍,具体的调用过程可以参考以下博客。此文主要记录调用numpy和release到测试机上遇到的问题。

问题描述

  1. Debug模式下PyImort_ImportModule()返回null,release正常
  2. PyParse_Turple()返回NULL
  3. PyImport_ImportModule第二次运行返回
  4. release到测试机上各种无法运行。

解决办法

问题1和2

python函数返回的不是python內建类型而是numpy之类的类型时常有发生,一般是python文件的路径问题导致无法import。如果是使用vs的话,可以观察输出栏,看编译过程是否将所需py文件包含进来。我在挣扎了一段时间后,决定还是不跟PyObjectArray死磕了,选择绕开numpy数组,在python函数返回前将ndarray通过toList()转为list数组,再在Qt一端使用PyList_GetItem()获取元素。注意一点,调用的python脚本或者函数必须是在命令行直接使用python能够运行的。 Python代码

    return [mfcc_featMean.tolist(),mfcc_featStd.tolist(),mfcc_featEntropy.tolist(),timeLast]

C++代码

        frameNums = PyList_Size(PyList_GetItem(pReturn, 0));
        PyArg_Parse(PyList_GetItem(pReturn, 3), "d", &timeLast);
        double tmp;
        for (int i = 0; i < frameNums; i++)
        {
            PyArg_Parse(PyList_GetItem(PyList_GetItem(pReturn, 0), i), "d", &tmp);
            mfcc_featMean.append(tmp);
        }

问题3

查阅资料知不能重复import,否则读取的是上一次import的cache。解决方法为直接在类内定义3个PyObject*成员变量,然后在类的构造函数进行初始化,那么这个类内就可以重复使用这个module和func了。

    #python初始化
    Py_Initialize();
    pModule = PyImport_ImportModule("qtHelper");
    pFunc1 = PyObject_GetAttrString(pModule, "getMfccAndRes");
    pFunc2 = PyObject_GetAttrString(pModule, "getClassificationRes");

问题4

分为两种情况:一,提示错误:一般是缺少dll或相关文件。二,点击无反应:测试机需要安装python环境和要调用的库,使用shell测试一下py文件是否能运行。

Reference

  1. List Obeject python官方文档
  2. C++和Python通信–知乎
  3. c++调用python脚本遇到的那些坑