c++/qt与Python交互,调用python函数接口、支持复杂传参类型、多线程调用、调用shell命令

1、c++支持线程中调用python函数接口;
2、支持python复杂参数类型如下:字典类型、嵌套列表类型;
支持QMap转python字典类型; QList/QVector转python列表、嵌套列表类型;
3、支持c++/qt多线程调用python函数;
4、python线程锁
5、c++调用shell命令

#include <pybind11/pybind11.h>
#include <pybind11//stl.h>
#include <pybind11/embed.h> // everything needed for embedding
#include "PyThreadStateLock.h"
#include "Python.h"
#include "windows.h"
#include "shellapi.h"
#include "atlstr.h"

一、初始化python

void MyTabWidget::pythonInit()
{
	if (!Py_IsInitialized())
	{
		// char* pwd;
		// if ((pwd=_getcwd(NULL, 0)) == NULL) {
		//     qDebug("getpwd error");
		// }
		// Py_SetPythonHome((wchar_t*)pwd);
		// python包目录
		// Py_SetPythonHome((wchar_t*)(L"C:\\Users\\ZZJ\\AppData\\Local\\Programs\\Python\\Python312"));

		 //调试时用下面绝对路径,正式版本用上面那一行
		Py_SetPythonHome((wchar_t*)(L"C:\\Python312"));

		Py_Initialize();
		if (!Py_IsInitialized()) {
			qDebug("Initial Python failed!");
		}
		else {
			PyRun_SimpleString("import sys;sys.path.append('.')");
			PyEval_InitThreads();
			// 启动子线程前执行,为了释放PyEval_InitThreads获得的全局锁,否则子线程可能无法获取到全局锁。
			PyEval_ReleaseThread(PyThreadState_Get());
			qDebug("Initial Python Success!");
		}
	}
}

二、适配于调用python函数的线程锁文件

PyThreadStateLock.h

//将全局解释器锁和线程的相关操作用类封装
#ifndef PYTHREADSTATELOCK_H
#define PYTHREADSTATELOCK_H
#include "Python.h"

class PyThreadStateLock
{
public:
    PyThreadStateLock(void)
    {
        _save = nullptr;
        nStatus = 0;
        nStatus = PyGILState_Check();   //检测当前线程是否拥有GIL
        if (!nStatus)
        {
            gstate = PyGILState_Ensure();   //如果没有GIL,则申请获取GIL
            nStatus = 1;
        }
        _save = PyEval_SaveThread();
        PyEval_RestoreThread(_save);
    }
    ~PyThreadStateLock(void)
    {
        _save = PyEval_SaveThread();
        PyEval_RestoreThread(_save);
        if (nStatus)
        {
            PyGILState_Release(gstate);    //释放当前线程的GIL
        }
    }

private:
    PyGILState_STATE gstate;
    PyThreadState* _save;
    int nStatus;

};

#endif // PYTHREADSTATELOCK_H

三、c++ 线程中调用函数接口

void QueryDataControl::ThreadEventPod5File(QString datPath, QList<RecordReadsNumberParam>& paramlist)
{
	class PyThreadStateLock PyThreadLock;   //线程锁 线程加载调用python函数 否则崩溃

	QString datatime = QDateTime::currentDateTime().toString("yyyyMMddhhmmss");
	std::string path = datPath.toStdString();
	const char* cStr = path.c_str();

	PyObject* pModule = PyImport_ImportModule("write_pod5");		//pointer file python.py 
	if (!pModule) 
	{
		qDebug() << "Can't open python file!\n";
		return;
	}

	//调用python函数
	PyObject* pFun = PyObject_GetAttrString(pModule, "writePod5");		//调用函数
	PyObject* pFun2 = PyObject_GetAttrString(pModule, "test5");		//调用函数
	PyObject* pFun3 = PyObject_GetAttrString(pModule, "add");			//调用函数

	//python 字典类型-----方法一
	PyObject* second_arg = Py_BuildValue("{s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:s,s:i,s:s,s:s,s:s}","expName", "man", "exp_time", "2015", "flow_cell_id", "man", "flow_cell_product_code", "man",
		"protocol_name", "Memob", "protocol_run_id", "man", "sequencing_kit", "man", "sequencer_position", "man", 
		"sequencer_position_type", "man", "software", "Memob", "sample_rate", 5000, "system_name", "man", 
		"system_type", "man", "pore_type", "man");

	//创建python 字典类型	  将QMap转化为python字典类型   方法二
	PyObject* pDict = PyDict_New();
	QString python_info_path = QCoreApplication::applicationDirPath() + QString("/auroch_win_v0.4/testInfo.txt");
	QMap<QString, QString> test_info;
	FileRelevance::LoadPythonTestInfo(python_info_path, test_info);
	for (auto& pair : test_info.toStdMap())
	{
		QString key = pair.first;
		QString value = pair.second;
		const char* name_value = value.toStdString().c_str();
		if (key == Trans("实验样本"))
			auto h2 = PyDict_SetItemString(pDict, "expName", Py_BuildValue("s", name_value));
		else if (key == Trans("实验日期"))
			auto h2 = PyDict_SetItemString(pDict, "exp_time", Py_BuildValue("s", datatime.toStdString().c_str()));
		else if (key == Trans("实验芯片"))
			auto h2 = PyDict_SetItemString(pDict, "flow_cell_id", Py_BuildValue("s", name_value));
		else if (key == Trans("实验仪器"))
			auto h2 = PyDict_SetItemString(pDict, "protocol_name", Py_BuildValue("s", name_value));
		else if (key == Trans("控速酶"))
			auto h2 = PyDict_SetItemString(pDict, "sequencing_kit", Py_BuildValue("s", name_value));
		else if (key == Trans("缓冲液"))
			auto h2 = PyDict_SetItemString(pDict, "sequencer_position", Py_BuildValue("s", name_value));
		else if (key == Trans("建库方式"))
			auto h2 = PyDict_SetItemString(pDict, "sequencer_position_type", Py_BuildValue("s", name_value));
		else if (key == Trans("蛋白"))
			auto h2 = PyDict_SetItemString(pDict, "pore_type", Py_BuildValue("s", name_value));
		else if (key == Trans("采样率"))
			auto h2 = PyDict_SetItemString(pDict, "sample_rate", Py_BuildValue("i", value.toInt()));
		else if (key == Trans("算法版本"))
			auto h2 = PyDict_SetItemString(pDict, "software", Py_BuildValue("s", name_value));
	}
	PyDict_SetItemString(pDict, "flow_cell_product_code", Py_BuildValue("s", "Default"));
	PyDict_SetItemString(pDict, "protocol_run_id", Py_BuildValue("s", "Default"));
	PyDict_SetItemString(pDict, "system_name", Py_BuildValue("s", "Default"));
	PyDict_SetItemString(pDict, "system_type", Py_BuildValue("s", "Default"));

	//python字典  方法三
	auto h1 = PyDict_SetItemString(pDict, "expName", Py_BuildValue("s", "human"));					//往字典类型变量中填充数据 
	auto h2 = PyDict_SetItemString(pDict, "exp_time", Py_BuildValue("s", "20240515160132"));		//往字典类型变量中填充数据 
	PyDict_SetItemString(pDict, "flow_cell_id", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "flow_cell_product_code", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "protocol_name", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "protocol_run_id", Py_BuildValue("s", "010302"));
	PyDict_SetItemString(pDict, "sequencing_kit", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "sequencer_position", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "sequencer_position_type", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "software", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "sample_rate", Py_BuildValue("i", 4000));
	PyDict_SetItemString(pDict, "system_name", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "system_type", Py_BuildValue("s", "human"));
	PyDict_SetItemString(pDict, "pore_type", Py_BuildValue("s", "human"));
	
	//python 嵌套列表类型
	PyObject* first_arg = Py_BuildValue("[[[d,d,d,d,d],i,i,d,s]]",1.2,2.6,3.8,9.6,15.99, 2,2,0.6,"hyh");
	if (pFun3)
	{
		//创建一个元祖
		PyObject* pArgs = PyTuple_New(2);							//设置参数,用python元组
		PyObject* arg1 = Py_BuildValue("i", 5);						//设置参数,用python元组
		PyObject* arg2 = Py_BuildValue("i", 6);						//设置参数,用python元组

		auto hyh = PyTuple_SetItem(pArgs, 0, arg1);				//i表示创建int型变量
		auto hyh2 = PyTuple_SetItem(pArgs, 1, arg2);			//i表示创建int型变量
		PyObject* pResule = PyObject_CallObject(pFun3, pArgs);
		auto resultValue = PyLong_AsLong(pResule);
		QString hyhy;

	}
	if (pFun2)
	{
		PyObject* args = PyTuple_New(1);
		auto h3 = PyTuple_SetItem(args, 0, pDict);					//0---序号  将字典类型变量添加到参数元组中 

		//auto h = PyTuple_SetItem(args, 0, second_arg);

		//PyObject* pResule = PyObject_CallObject(pFun2, args);
		//if (pResule)
		//{
		//	//处理返回值: 

		//	int size = PyDict_Size(pResule);
		//	PyObject* pNewAge = PyDict_GetItemString(pResule, "sample_rate");
		//	PyObject* pNewAge1 = PyDict_GetItemString(pResule, "expName");
		//	PyObject* pNewAge2 = PyDict_GetItemString(pResule, "exp_time");

		//	int test;
		//	char* name;
		//	char* time;
		//	PyArg_Parse(pNewAge, "i", &test);
		//	PyArg_Parse(pNewAge1, "s", &name);
		//	PyArg_Parse(pNewAge2, "s", &time);
		//	QString str_name(name);
		//	QString str_time(time);
		//}

		//QList<float> datas;
		//datas.append(0.56);
		//datas.append(10.56);
		//datas.append(20.56);
		//datas.append(30.56);
		//datas.append(120.56);
		//datas.append(20.56);

		//PyObject* pList1 = PyList_New(datas.size());  // 创建一个长度为3的列表
		//for (int i = 0; i < datas.size(); i++)
		//{
		//	PyList_SetItem(pList1, i, PyFloat_FromDouble(datas.at(i)));  // 在索引1处插入浮点值3.14
		//}

		//PyObject* pList = PyList_New(5);		// 创建一个长度为4的列表
		//PyList_SetItem(pList, 0, pList1);
		//PyList_SetItem(pList, 1, PyLong_FromLong(10));
		//PyList_SetItem(pList, 2, PyLong_FromLong(20));
		//PyList_SetItem(pList, 3, PyFloat_FromDouble(2.68));
		//PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));

		//PyObject* args = PyTuple_Pack(1, pList);  // 将列表打包为参数元组


		//嵌套列表
		PyObject* output_args_list = PyList_New(paramlist.size());
		;
		for (int k = 0; k < paramlist.size(); k++)
		{
			auto param = paramlist.at(k);
			PyObject* pList1 = PyList_New(param.datas.size());  // 创建一个长度为3的列表
			for (int i = 0; i < param.datas.size(); i++)
			{
				PyList_SetItem(pList1, i, PyFloat_FromDouble(param.datas.at(i)));  // 在索引1处插入浮点值3.14
			}

			PyObject* pList = PyList_New(5);		// 创建一个长度为4的列表
			PyList_SetItem(pList, 0, pList1);
			PyList_SetItem(pList, 1, PyLong_FromLong(param.channel));
			PyList_SetItem(pList, 2, PyLong_FromLong(param.eventId));
			PyList_SetItem(pList, 3, PyFloat_FromDouble(param.begin_time));
			PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));

			PyList_SetItem(output_args_list, k, pList);
		}
		PyObject* args_list = PyTuple_Pack(1, output_args_list);  // 将列表打包为参数元组
		PyObject* pResule = PyObject_CallObject(pFun2, args_list);
	}

	if (pFun)
	{
		//创建python列表 嵌套列表
		//PyObject* hyh_arge = Py_BuildValue("[[[d,d,d,d,d],i,i,d,s],[[d,d,d,d,d],i,i,d,s]]", 1.2, 2.6, 3.8, 9.6, 15.99, 2, 3, 0.6, "hyh", 1.2, 2.6, 3.8, 9.6, 15.99, 2, 3, 0.6, "hyh");

		//QList 自定义结构体类型
		PyObject* output_args_list = PyList_New(paramlist.size());
		for (int k = 0; k < paramlist.size(); k++)
		{
			auto param = paramlist.at(k);
			PyObject* pList1 = PyList_New(param.datas.size());  // 创建一个长度为3的列表
			for (int i = 0; i < param.datas.size(); i++)
			{
				PyList_SetItem(pList1, i, PyFloat_FromDouble(param.datas.at(i)));  // 在索引1处插入浮点值3.14
			}

			PyObject* pList = PyList_New(5);		// 创建一个长度为4的列表
			PyList_SetItem(pList, 0, pList1);
			PyList_SetItem(pList, 1, PyLong_FromLong(param.channel));
			PyList_SetItem(pList, 2, PyLong_FromLong(param.eventId));
			PyList_SetItem(pList, 3, PyFloat_FromDouble(param.begin_time));
			PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));

			PyList_SetItem(output_args_list, k, pList);
		}

		单个结构体类型
		//auto param = paramlist[0];
		//PyObject* pList1 = PyList_New(param.datas.size());  // 创建一个长度为3的列表
		//for (int i = 0; i < param.datas.size(); i++)
		//{
		//	PyList_SetItem(pList1, i, PyFloat_FromDouble(param.datas.at(i)));  // 在索引1处插入浮点值3.14
		//}

		//PyObject* pList = PyList_New(5);		// 创建一个长度为4的列表
		//PyList_SetItem(pList, 0, pList1);
		//PyList_SetItem(pList, 1, PyLong_FromLong(param.channel));
		//PyList_SetItem(pList, 2, PyLong_FromLong(param.eventId));
		//PyList_SetItem(pList, 3, PyFloat_FromDouble(param.begin_time));
		//PyList_SetItem(pList, 4, PyUnicode_FromString("hyh"));
		//PyObject* args_list = PyTuple_Pack(1, pList);  // 将列表打包为参数元组


		PyObject* pArgs = PyTuple_New(3);
		auto h = PyTuple_SetItem(pArgs, 0, output_args_list);
		auto h2 = PyTuple_SetItem(pArgs, 1, pDict);
		auto h3 = PyTuple_SetItem(pArgs, 2, Py_BuildValue("s", cStr));

		PyObject* pResule = PyObject_CallObject(pFun, pArgs);	
		if (pResule)
		{
			char* tse;
			PyArg_Parse(pResule, "s", &tse);
			QString srt1(tse);
		}
		PyObject_CallFunction(pFun, NULL);    //解决线程崩溃情况
	}
}

四、c++调用shell命令

void QueryDataControl::startDorado()
{
	LPCWSTR filePath = L"./dorado-0.3.4-win64/bin";
	CString strPath;
	GetModuleFileName(NULL, strPath.GetBufferSetLength(MAX_PATH + 1), MAX_PATH + 1);
	int pos = strPath.ReverseFind('\\');
	strPath = strPath.Left(pos + 1);
	auto dorado_path = strPath + "dorado-0.3.4-win64\\bin\\dorado.exe basecaller ";
	auto dorado_model = strPath + "dorado-0.3.4-win64\\model ";
	auto pod5_path = strPath + "Pod5\\ --emit-fastq>";
	auto fastq_path = strPath + "fastq\\test\\";
	auto fastq_file_str = QDateTime::currentDateTime().toString("yyyyMMddhhmmss") + ".fastq";
	std::string str = fastq_file_str.toStdString(); // 将QString转换为std::string
	CString fastq_file(str.c_str()); // 将std::string转换为CString
	auto cmd_str = dorado_path + dorado_model + pod5_path + fastq_path + fastq_file;

	QString m_fast_path_save = QCoreApplication::applicationDirPath() + QString("/fastq/test/")+ QString::fromStdString(str);
	m_save_fastqs.append(m_fast_path_save);

	wchar_t commandLine[MAX_PATH * 2];
	swprintf(commandLine, MAX_PATH * 2, L"/K \"%s\"", cmd_str);

	HINSTANCE hNewExe = ShellExecute(NULL, L"open", L"cmd.exe", commandLine, filePath, SW_SHOWNORMAL/*SW_HIDE*/);
}

void QueryDataControl::startAuroch() 
{
	wchar_t currentDirectory[MAX_PATH];
	GetCurrentDirectory(MAX_PATH, currentDirectory);     //D:\home_work_new\MeMob96_Code_20230911\MeMob

	CString strPath;
	GetModuleFileName(NULL, strPath.GetBufferSetLength(MAX_PATH + 1), MAX_PATH + 1);
	int pos = strPath.ReverseFind('\\');
	strPath = strPath.Left(pos + 1);

	wchar_t aurochDirectory[MAX_PATH];
	swprintf(aurochDirectory, MAX_PATH, L"%sauroch_win_v0.4", strPath);

	wchar_t commandLine[MAX_PATH * 2];
	swprintf(commandLine, MAX_PATH * 2, L"/K cd /d \"%s\" && powershell -File auroch_v0.4.ps1 config.ps1", aurochDirectory);
	ShellExecute(NULL, L"runas", L"cmd.exe", commandLine, NULL, SW_SHOWNORMAL);
}
  • 9
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

星空上的鲸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值