## 序言
上篇介绍了Qt中调用python相关注意事项,这篇着重介绍C++(Qt)如何嵌入python,并且使用python中函数或者类。注意使用头文件声明python.h, 以及对应的python.lib
## 参数说明
一、初始化
Py_Initialize()
python模块初始化操作。
二、结束收尾
Py_Finalize()
释放相关模块操作。
三、导入模块
PyImport_ImportModule()
python一个文件其实就是一个模块,导入所需要的文件名即可前提是python搜索路径中有。
qt调用python模块时,比如说myDemo.py ,它会查找目录如下
程序的根目录
PYTHONPATH环境变量设置的目录
标准库的目录
任何能够找到的.pth文件的内容
第三方扩展的site-package目录
优先去 D:\Python\Python37-32安装系统目录下或者其他库目录下去找py文件 如果找不到,再去有路径pth内容搜索。
四、返回模块里函数
PyObject_GetAttrString()
返回模块里面的函数.
五、传递参数给python
Py_BuildValue()
建立一个参数元组,一般都是用这个函数来建立元组,然后将这个元组作为参数传递给python里面的函数。
六、调用函数
PyEval_CallObject()
调用函数,并把“Py_BuildValue”建立的元组作为参数传递给被调用的函数。
七、返回python的结果
PyArg_Parse()
将python调用的结果返回。
## 代码
python
import matplotlib.pyplot as plt
import numpy as np
import multiprocessing
def getPic(str):
print ('enter getPic...', str)
x = np.arange(9)
y = np.sin(x)
z = np.cos(x)
print ('enter getPic...')
plt.plot(x, y, marker="*", linewidth=3, linestyle="--", color="orange")
plt.plot(x, z)
plt.title("matplotlib")
plt.xlabel("height")
plt.ylabel("width")
plt.legend(["Y","Z"], loc="upper right")
plt.grid(True)
plt.show()
def add(a = 3, b = 4):
print('a + b = ', a+b);
return a+b
#pragma push_macro("slots")
#undef slots
#include <Python.h>
#pragma pop_macro("slots")
方式一 直接简单调用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Py_Initialize();
PyRun_SimpleString("print('hello world!')");
Py_Finalize();
}
方式二 带有参数传递的调用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Py_Initialize();
//如果初始化失败,返回
if(!Py_IsInitialized())
{
qDebug()<<"initial failure!";
return a.exec();
}
//加载模块,模块名称为myDemo,就是myDemo.py文件
PyObject *pModule = PyImport_ImportModule("myDemo");
//如果加载失败,则返回
if(!pModule)
{
qDebug()<<"load failure";
return a.exec();
}
//加载函数getPic
PyObject* pDict = PyModule_GetDict(pModule);
//从字典属性中获取函数
PyObject* pFunc = PyDict_GetItemString(pDict, "getPic");
if(pFunc && PyCallable_Check(pFunc))
{
//调用函数
//参数类型转换,传递一个字符串。将c/c++类型的字符串转换为python类型,元组中的python类型查看python文档
PyObject* pArg = Py_BuildValue("(s)", "getPic");
PyEval_CallObject(pFunc, pArg); //调用直接获得的函数,并传递参数
}
//如果失败则返回
else
{
qDebug()<<"load function failure";
return a.exec();
}
Py_Finalize();
}
方式三 带有返回结果的
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
//进行初始化
Py_Initialize();
//如果初始化失败,返回
if(!Py_IsInitialized())
{
qDebug()<<"initial failure!";
return a.exec();
}
//加载模块,模块名称为myDemo,就是myDemo.py文件
PyObject *pModule = PyImport_ImportModule("myDemo");
//如果加载失败,则返回
if(!pModule)
{
qDebug()<<"load failure";
return a.exec();
}
PyObject* pDict = PyModule_GetDict(pModule);
PyObject* pFunc = PyDict_GetItemString(pDict, "add"); //从字典属性中获取函数
PyObject* pArg = Py_BuildValue("(i, i)", 1, 2); //参数类型转换,传递两个整型参数
PyObject* result = PyEval_CallObject(pFunc, pArg); //调用函数,并得到python类型的返回值
int sum;
PyArg_Parse(result, "i", &sum); //将python类型的返回值转换为c/c++类型
qDebug()<<"sum = "<<sum;
Py_Finalize();
}
这两种方法不适合调用哪种需要重新开启进程做其他逻辑处理稍微复杂的事。只适合简单的参数传递并且有返回结果的, 对于如果参数是元组,列表之类那目前没有提供,需要自己查查。
方案四 直接暴力开启进程调用python
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug()<< QApplication::applicationDirPath();
QString program = "D:\\Python\\Python37-32\\python.exe";
QStringList cmd;
cmd<<"E:\\qt\\pyQt\\PYQTOne\\myDemo.py";
QProcess::execute(program, cmd);
return a.exec();
}
该方式不管你是否需要开启进程处理绘图或者其他复杂逻辑的事情,结果都可以。但是你想调用的逻辑处理 的必须自己在python里本文件调用。
关于python搜索路径参考这篇网址:
https://blog.csdn.net/fitzzhang/article/details/78988155
网址:
https://segmentfault.com/a/1190000000531613