VS2017 C/C++调用python脚本文件


在实际的工作中,为了方便利用python写的程序(因为python中有很多功能强大的函数库),有时需要进行c、c++与python的混合编程,特别是需要在c程序中调用python脚本。这时候就到了python展现自己"胶水语言"的一面了。

值得注意的是

对于纯python程序而言,用c程序来调用是比较适合的,如果python程序中包含了其他第三方库,则调用极可能出错,且不易查明原因。往往一个大型的python项目,比如SSD目标检测等,都是需要调用很多第三方库,而且多模块互相交织,虽然说当你把python项目环境的路径在VS里面配置好了,相对路径搞明白了,理论上应该没啥问题,但是实践中还是会有一些令人头大的错误出来,所以如果你只想用python项目的生成结果的话,可以通过文件进行连接

下面就简单说在c语言里面怎么调用python

1、环境配置

①将vs工程配置为和你的pytho环境里的解释器的为啥相同,比如你用到是X64的python环境,VS工程就要配置成X64
在这里插入图片描述
②添加包含目录和库目录, 添加你的python项目环境里面的include和libs文件夹路径,比如 D:\anaconda\include

  • 打开解决方案资源管理器,在右侧的项目名称右击选择属性在这里插入图片描述

  • 左边找到VC++目录,在包含目录和库目录添加对应的include和libs路径,建议手动在资源管理器里面选择
    在这里插入图片描述

  • 添加依赖项
    找到链接器-输入,附加依赖项,添加libs目录里面的python37_d.lib,注意这里一开始是没有这个的,只有pyth37.lib,这里复制一份重命名为python37_d.lib,因为VS默认会检测后者,不改的话肯能会报错。
    在这里插入图片描述
    配置完成之后先来看一个简单的例子

2.一个例子

demo_test.py

#coding:utf-8
import os

def run(com):
   return com
def main():
    print(run(("4",3)))
    
if __name__=='__main__':
   main()
    

源.cpp

#include<iostream>
#include <Python.h>

using namespace std;

int main()
{
	//***python调用***//
	//初始化python模块
	Py_Initialize();
	// 检查初始化是否成功  
	if (!Py_IsInitialized())
	{
		cout << "初始化失败" << endl;
		Py_Finalize();
	}

	PyObject *pModule;
	PyObject*pFunc = NULL;
	PyObject*pArg = NULL;
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");//设置python模块,搜寻位置,文件放在.cpp文件一起
	

	pModule = PyImport_ImportModule("demo_test");//Python文件名     
	if (!pModule) {
		cout << "py文件导入失败" << endl;
		Py_Finalize();
	}
	else{
		pFunc = PyObject_GetAttrString(pModule, "run");//Python文件中的函数名  
		if (!pFunc) {
			cout << "函数导入失败" << endl;
			Py_Finalize();
		}
		
		PyObject* pyParams = Py_BuildValue("(s)","helllo world!");//c++类型转python类型

		char * result1;
		pArg = PyEval_CallObject(pFunc, pyParams);//调用函数
		PyArg_Parse(pArg, "s", &result1);//python类型转c++类型
		cout << result1<< endl;


	system("pause");
}

在这里插入图片描述

这里注意,vs的当前目录表示的是。vcxproj文件所在的位置,用".“表示,上级目录用”. ."
在这里插入图片描述

看不懂上面的函数没关系,下面全面详细介绍,Python.h 头文件里面都有哪些API

3,API详解

1、运行Python指令

PyRun_SimpleString("print(os.getcwd(),a)");
pyext.eval(R"(a+='qwer')");

2、加载Python模块

PyObject * pModule =PyImport_ImportModule("tp"); //test:Python文件名,若脚本有错则返回空
PyRun_SimpleString("import os");

3、给Python的变量赋值

对于数值,使用Py_BuildValue:

Py_BuildValue("") None
Py_BuildValue("i", 123) 123
Py_BuildValue("iii", 123, 456, 789) (123, 456, 789)
Py_BuildValue("s", "hello") 'hello'
Py_BuildValue("ss", "hello", "world") ('hello', 'world')
Py_BuildValue("s#", "hello", 4) 'hell'
Py_BuildValue("()") ()
Py_BuildValue("(i)", 123) (123,)  
Py_BuildValue("(ii)", 123, 456) (123, 456)
Py_BuildValue("(i,i)", 123, 456) (123, 456)
Py_BuildValue("[i,i]", 123, 456) [123, 456]
Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) {'abc': 123, 'def': 456}

对于其他数据结构,使用相应的函数设置,例如:

PyObject *pArgs = PyTuple_New(1);
PyObject *pDict = PyDict_New();  //创建字典类型变量 
PyDict_SetItemString(pDict, "Name", Py_BuildValue("s", "WangYao")); //往字典类型变量中填充数据 
PyDict_SetItemString(pDict, "Age", Py_BuildValue("i", 25)); //往字典类型变量中填充数据 
PyTuple_SetItem(pArgs, 0, pDict);//0---序号 将字典类型变量添加到参数元组中 

构造好对象以后,通过PyObject_SetAttrString来设置进入Python中:

PyObject *ps=PyUnicode_DecodeUTF8(val,strlen(val),"ignore"); //构造了一个对象
PyObject_SetAttrString(p_main_Module,key,ps); //设置

4、获取Python变量的值

首先取得变量的指针,然后通过PyArg_Parse解析

pModule =PyImport_ImportModule("__main__");
pReturn = PyObject_GetAttrString(pModule, "a"); //可以获得全局变量
int size = PyDict_Size(pReturn); 
PyObject *pNewAge = PyDict_GetItemString(pReturn, "Age"); 
int newAge;
PyArg_Parse(pNewAge, "i", &newAge); 

对于元组的解析:

int ok;
ok = PyArg_ParseTuple(args, "s", &s); //Python call: f('whoops!')
ok = PyArg_ParseTuple(args, "lls", &k, &l, &s);//Python call: f(1, 2,'three')
ok = PyArg_ParseTuple(args, "(ii)s#", &i, &j, &s, &size);//Python call: f((1, 2), 'three')
ok = PyArg_ParseTuple(args, "s|si", &file, &mode, &bufsize);//Python calls:
//f('spam')
//f('spam', 'w')
//f('spam', 'wb', 100000)

5、调用Python函数

PyObject * pfun=PyObject_GetAttrString(pModule, "testdict"); //testdict:Python文件中的函数名
PyObject *pReturn = PyEval_CallObject(pfun, pArgs); //调用函数

6、设置函数让Python调用

首先定义c函数,然后声明方法列表,然后声明模块,然后增加这个模块,最后调用

static int numargs=1890;
static PyObject* emb_numargs(PyObject *self, PyObject *args) //C函数
{
  if(!PyArg_ParseTuple(args, ":numargs"))
    return NULL;
  return PyLong_FromLong(numargs);
}
static PyMethodDef EmbMethods[] = { //方法列表
  {"numargs", emb_numargs, METH_VARARGS,
   "Return the number of arguments received by the process."},
  {NULL, NULL, 0, NULL}
};
static PyModuleDef EmbModule = { //模块声明
  PyModuleDef_HEAD_INIT, "emb", NULL, -1, EmbMethods,
  NULL, NULL, NULL, NULL
};
static PyObject* PyInit_emb(void) //模块初始化函数
{
  return PyModule_Create(&EmbModule);
}
//增加模块:
PyImport_AppendInittab("emb", &PyInit_emb); //增加一个模块
发布了79 篇原创文章 · 获赞 514 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/i6223671/article/details/99832186