QT C++中调用python脚本时,import第三方库失败问题解决

2024-01-07 18:23:31

QT C++中调用python脚本时,import第三方库失败问题解决



前言

项目需要,计划通过C++的QT调用Python脚本,实现更快的算法实现,并集成在项目软件上。但是,在按照网上教程,配置好C++调用Python脚本的环境后,在调用(import)对应路径下的py文件时,基本没有问题。但是,一旦调用numpy、matplotlib时,则PyImport_ImportModule函数即会返回失败! 因此,这里重点针对import第三方库,却PyImport_ImportModule失败的问题,进行解决。关于配置C++调用Python脚本的环境,参考上述链接即可,并不复杂。


一、问题复现

首先,对具体问题进行更加细致的复现。在C++代码中,具体代码如下。

// 1. 设置Python的运行环境目录
    Py_SetPythonHome(L"D:/Software/anaconda3/envs/xxxx");


    // 2. 初始化python解释器
    Py_Initialize();

    // 2.1 检查初始化是否成功
    if (!Py_IsInitialized()) {
        qDebug() << "Python init fail";
        Py_Finalize();
    }

    // 3.1 执行Python脚本语句
    PyRun_SimpleString("print('I am Python!')");

    // 3.2 初始化python系统文件路径,保证可以访问到 .py文件
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('E:/Code/xxxx/')");

    // 3.3 将文件作为模块,import导入,不需写后缀
    PyObject* pModule = PyImport_ImportModule("MyTest");
    if (pModule == NULL) {
       qDebug() << "module not found";
       return;
    }

    // 3.4 调用函数
    PyObject* pFunc = PyObject_GetAttrString(pModule, "test");
    if (!pFunc || !PyCallable_Check(pFunc)) {
       qDebug() << "not found function test";
        return;
    }

在这里,MyTest.py文件内,代码如下。

import numpy as np
from matplotlib import pyplot as plt
import time
import math

def test():
    print("hello!")

此时,若将MyTest.py中import的四个模块语句注释,则程序没有任何问题,正常运行。但是,若不注释那四句,则 PyObject* pModule = PyImport_ImportModule(“MyTest”)会返回NULL。这时,便会给我们产生错觉:似乎该环境下,调用通过pip install安装的第三方库,便会失败,即需要进一步配置这些第三方库的环境。

二、调试过程

首先,便是按照上述思路,进行百度谷歌寻找答案,主要是配置python的库文件的环境变量等,这里不赘述,总之,这并不能解决问题!
后来,突然发现,在C++代码中,有这么一句:

PyRun_SimpleString("import sys");

调试发现,该句代码是成功运行的,所以,便推倒前述结论:该环境下,调用通过pip install安装的第三方库,便会失败。那么,也就是说,仅是上述的某些库,import失败了,而非所有第三方库!于是,分别对MyTest.py中的import部分代码轮流注释,如下:

import numpy as np
# from matplotlib import pyplot as plt
# import time
# import math

def test():
    print("hello!")

结果发现,当单独import time与math时,PyObject* pModule = PyImport_ImportModule(“MyTest”)返回并不为空,也就是说是导入成功的!因此,可以正确推出结论:PyImport_ImportModule在执行Import numpy与matplotlib时,会失败。 但是,为什么会失败呢?仅从上述代码中的返回结果,仍然无法看出错误原因。于是,修改C++代码,将下述两行代码,加入到PyRun_SimpleString(“import sys”)之后。

PyRun_SimpleString("import numpy");
PyRun_SimpleString("import matplotlib");

于是,背后真正的错误便迎面儿来了。当import numpy时,错误为:

and make sure that they are the versions you expect.
Please carefully study the documentation linked above for further help.

Original error was: DLL load failed while importing _multiarray_umath: 找不到指定的模块。

当import matplotlib时,错误为:

ImportError: cannot import name 'Image' from 'PIL' (unknown location)

三、问题解决

其实,当背后错误出现时,再解决问题就很好办了,对应去搜背后错误的解决方法即可。我相应参考numpy问题解决matplotlib问题解决,两个问题便都迎刃而解了。这里总结一下。

1 numpy问题解决

重新安装numpy即可:

pip uninstall numpy
pip install numpy

2 matplotlib问题解决

pip uninstall pillow
pip install pillow

可以发现,都是通过重新安装库或者关键依赖库后,问题得以解决!至于具体原因是什么,还不是非常清楚,也由于时间问题,就不深入挖掘了,希望后续有大佬搞清楚以后,欢迎交流讨论!

四、补充说明

本部分,为后续补充内容。在完成本篇博客后,后续项目推进上,又碰到了很多类似问题,例如同样在C++调用Python拓展模块时,报错:

ImportError: DLL load failed while importing cv2: 找不到指定的模块。

此时,我按照本文提出方法,卸载opencv后继续安装,也进一步安装了opencv-contrib-python模块等,均未解决问题。后来考虑,是否为opencv版本太高呢,于是将opencv降版本至4.5.1.48,问题解决!至此,大概可以为为本文的问题形成一个结论:当出现找不到指定模块、DLL加载失败等类似问题时,可考虑一种很大可能性,是该库的版本与环境不匹配,可能版本太旧,但同样也可能版本太新!此时,可调整几个版本测试,很多类似问题可能也就此解决了!
另外,在本部分的研究内容中,需要自行编译支持gstreamer编码器的opencv,感觉这类opencv库应该需求量很大,但是却没有人提供编译好的库,故此在这里提供链接

五、参考资料

最后,感谢各位大佬提供的前人经验:
[1] alxe_made: Qtcreator中C++调用python方法
[2] HJ: 成功解决ImportError: cannot import name ‘image‘ from ‘PIL‘(unknown location)
[3] 衷科知眠: 成功解决ImportError: cannot import name ‘image‘ from ‘PIL‘(unknown location)

文章来源:https://blog.csdn.net/qq_38606680/article/details/135374829
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。