【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件

本篇博客主要讲述c++环境下调用python脚本的主要步骤以及配置,并调用函数进行实例演示,特别注意python和vs的环境要一致。

【1】环境配置

本文环境:w7+python3.6

【1.1】include文件和lib文件的复制。

(1)源文件位置,anconda目录下的两个文件。

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第1张图片

(2)复制后的文件位置,红色区间内为复制过来的两个文件,其他文件为应用程序的项目文件夹。

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第2张图片

【1.2 】环境配置主要由三部分组成:包含目录、库目录、附加依赖库。

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第3张图片

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第4张图片

【1.3】无法打开 python36_d.lib 的问题,配置pyconfig.h文件,python36_d.lib改为python36.lib

(1)打开文件

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第5张图片

(2)配置文件,主要修改两个位置,如下所示

位置1 更改结果如方框所示

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第6张图片

位置2 注释掉红色方框内部的代码

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第7张图片

参考文献 无法打开 python36_d.lib 的问题

【2】无第三方库的代码以及结果展示

【2.1】python代码

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   hello.py
@Time    :   2021/04/14 10:21:16
@Author  :   Jian Song 
@Contact :   [email protected]
@Desc    :   None
'''

# here put the import lib

import numpy as np

def add_num(a,b):
    return a+b

def helloya():
    print("hello,song")

def UseNumpy():
    for index in np.arange(10):   
        print("%d number:%d "%(index,index*index+1))

if __name__=="__main__":
    UseNumpy()

【2.2】c++代码

// PythonCpp.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 
#include 
#include   
#include 

using namespace std;

/*
c++调用python脚本文件
参考文献
[1] VS2017 C/C++调用python脚本文件  
	https://blog.csdn.net/i6223671/article/details/99832186
[2]	C++调用Python函数(二)——调用函数并输出返回值
	https://blog.csdn.net/weixin_38285131/article/details/81224381
*/

int main()
{
	Py_Initialize();//使用python之前,要调用Py_Initialize();这个函数进行初始化
	if (!Py_IsInitialized())
	{
		printf("Initialized was failed!");
		return 0;
	}

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");//这一步很重要,修改Python路径

	PyObject * pModule = NULL;//声明变量
	PyObject * pFunc = NULL;// 声明变量

	pModule = PyImport_ImportModule("hello");//这里是要调用的文件名hello.py
	if (pModule == NULL){cout << "Sorry,don't find file!" << endl;}

	//------------------------[1]调用具有返回值的函数------------------------------------
	pFunc = PyObject_GetAttrString(pModule, "add_num");//这里是要调用的函数名
	PyObject* args = Py_BuildValue("(ii)", 1, 103);//给python函数参数赋值
	PyObject* pRet = PyObject_CallObject(pFunc, args);//调用函数
	int res = 0;
	PyArg_Parse(pRet, "i", &res);//转换返回类型
	cout << "res:" << res << endl;//输出结果


	//------------------------[2]调用没有返回值的函数------------------------------------
	PyObject * pFunc1 = NULL;// 声明变量
	pFunc1 = PyObject_GetAttrString(pModule, "helloya");//这里是要调用的函数名
	PyObject* pRet1 = PyObject_CallObject(pFunc1,nullptr);//调用函数


	//------------------------[3]调用使用numpy库的函数------------------------------------
	PyObject * pFunc2 = NULL;// 声明变量
	pFunc2 = PyObject_GetAttrString(pModule, "UseNumpy");//这里是要调用的函数名
	PyObject* pRet2 = PyObject_CallObject(pFunc2, nullptr);//调用函数


	Py_Finalize();//调用Py_Finalize,这个根Py_Initialize相对应的。

	return 0;
}

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第8张图片

参考文献:【1】C++调用python的那些坑(详细教程步骤)

                 【2】 C++调用Python函数(二)——调用函数并输出返回值

【3】含有类的代码展示

【3.1】普通函数和不需要初始化的类(不含有__init__函数的类)

含有__init__函数的类需要对类进行初始化,需要设置参数,然后带入;不含__init__函数的类可直接调用,在调用过程中输入参数即可。

注意注意  self参数在初始化时不能被当成形参,比如__init__(self,a,b),初始化时候只需要考虑(a,b)参数。

在调用类中的函数时,如setage(self,a),输入参数时self可省略,也可以输入但是设置为空。

(self,a)-》(s,i)->(" ",10)  //类型转换见末尾

【3.1.1】  python代码

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   test2.py
@Time    :   2021/04/15 09:43:36
@Author  :   Jian Song 
@Contact :   [email protected]
@Desc    :   None
'''

# here put the import lib

def hello(s):
    print("hello world")
    print(s)
 
 
def arg(a, b):
    print('a=', a)
    print('b=', b)
    return a + b
 
 
class Test:
    def __init__(self):
        print("init")
 
    def say_hello(self, name):
        print("hello", name)
        return name

【3.1.2】 c++代码

#include "pch.h"
#include 
#include 
#include   
#include 

using namespace std;

/*
C++ 调用 Python3.6中的各种坑:
https://blog.csdn.net/lingtianyulong/article/details/81146495?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_title-8&spm=1001.2101.3001.4242

*/

int main5(int argc, char* argv[])
{

	//初始化python
	Py_Initialize();
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");

	//定义python类型的变量
	PyObject *pModule = NULL;
	PyObject *pFunc = NULL;
	PyObject *pArg = NULL;
	PyObject *result = NULL;
	PyObject *pClass = NULL;
	PyObject *pInstance = NULL;
	PyObject *pDict = NULL;

	//直接运行python代码
	PyRun_SimpleString("print('python start')");
	//引入模块
	pModule = PyImport_ImportModule("test2");
	if (!pModule)
	{
		cout << "Import Module Failed" << endl;
		system("pause");
		return 0;
	}

	//获取模块字典属性
	pDict = PyModule_GetDict(pModule);

	//-----------------------获取模块中的函数方法1:直接调用---------------------------
	//直接获取模块中的函数
	pFunc = PyObject_GetAttrString(pModule, "hello");
	//参数类型转换,传递一个字符串。将c/c++类型的字符串转换为python类型,元组中的python类型查看python文档
	pArg = Py_BuildValue("(s)", "hello charity");
	// 调用直接获得的函数,并传递参数
	PyEval_CallObject(pFunc, pArg);

	//-----------------------获取模块中的函数方法2:字典属性获取---------------------------
	// 从字典属性中获取函数
	pFunc = PyDict_GetItemString(pDict, "arg");
	// 参数类型转换,传递两个整型参数
	pArg = Py_BuildValue("(i, i)", 1, 2);
	// 调用函数,并得到 python 类型的返回值
	result = PyEval_CallObject(pFunc, pArg);
	// c 用来保存 C/C++ 类型的返回值
	int c = 0;
	// 将 python 类型的返回值转换为 C/C++类型
	PyArg_Parse(result, "i", &c);
	cout << "a+b = " << c << endl;

	//-----------------------获取模块中的类的成员函数---------------------------
	//--------------------------这个类没有进行初始化,直接在调用的时候加载参数----------------------------------
	// 【1】通过字典属性获取模块中的类 
	pClass = PyDict_GetItemString(pDict, "Test");
	if (!pClass)
	{
		cout << "获取模块中的类失败" << endl;
		system("pause");
		return 0;
	}
	// 【2】实例化获取的类
	pInstance = PyInstanceMethod_New(pClass);
	//【3】调用类的方法
	result = PyObject_CallMethod(pInstance, "say_hello", "(s,s)", "", "charity");
	//【4】输出返回值
	char* name = NULL;
	PyArg_Parse(result, "s", &name);   //这个函数的第二个参数相当扯淡,具体看下文的英文,类型使用字符来表示的,例如“s”代表 str "i" 代表int,个人感觉相当扯淡
	printf("%s\n", name);
	PyRun_SimpleString("print('python end')");
	   
	//释放python
	Py_Finalize();
	system("pause");
	return 0;

}

参考文献:【1】c++调用python的代码、函数、类

【3.2】需要初始化的类(含有__init__函数的类)

【3.2.1】  python代码

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   myclass1.py
@Time    :   2021/04/15 16:30:16
@Author  :   Jian Song 
@Contact :   [email protected]
@Desc    :   None
'''

# here put the import lib
	
import sys
# 类
class Person():
	__age = 18
	__food = 'whatever'   

	def __init__(self,a):
		self.__age=a
		print("初始化完成")

	def WhatEat(self):
		print('no mind!')
		
	def EatThis(self,foodName):
		self.__food = foodName
		
	def GetEat(self):
		return self.__food
		
	def GetAge(self):
		return self.__age

【3.2.2】  c++代码

#include "pch.h"
#include 
#include 
#include   
#include 

using namespace std;
/* 
该程序主要是用来调用python中的类
	参考文献:
	[1]https://blog.csdn.net/qq_30460949/article/details/103087392?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&dist_request_id=&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
    [2] https://www.cnblogs.com/Hisin/archive/2012/02/27/2370590.html
	[3]Qt C++调用Python方法以及类(类的实例化、成员函数调用
	   https://blog.csdn.net/qq1512165940/article/details/103617894

	(1)参数传递有两种方法: 直接传递和元组传递

	(2)函数调用也存在两种方法: 直接调用和类对象调用

	本程序参考文献:C++ —— 调用Python3函数与类对象
		            https://blog.csdn.net/automoblie0/article/details/102461477	
					C++调用Python方法以及类(类的实例化、成员函数调用
					https://blog.csdn.net/qq1512165940/article/details/103617894

*/


int main()
{
	// 使用python之前,要调用Py_Initialize();这个函数进行初始化
	Py_Initialize();
	if (!Py_IsInitialized())
	{
		printf("初始化失败!");		
		return -1;
	}

	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");   //这一步很重要,修改Python路径

	//【1】加载.py文件
	PyObject * pModule = nullptr;                  //声明变量
	pModule = PyImport_ImportModule("myclass1");   //这里是要调用的文件名py.py,(注意把test.py改名,python自带测试模组且优先级高于用户的)
	if (pModule == nullptr)
	{
		cout << "没找到" << endl;
		return -2;
	}

	//【2】获取.py文件中的类
	// 模块的字典列表
	PyObject* pDict = PyModule_GetDict(pModule);
	if (!pDict)
	{
		cout << "Cant find dictionary." << endl;
		return -1;
	}

	// 获取Person类
	PyObject* pClasspPerson = PyDict_GetItemString(pDict, "Person");
	if (!pClasspPerson)
	{
		cout << "Cant find Person class." << endl;
		return -1;
	}

	//【3】对类进行初始化
	//构建类构造函数的参数,就是__init__函数,__init__(self,a),self不能算参数,所以只存在一个参数
	//__init__(self,a),self不能算参数,所以只存在一个参数
	//__init__(self, a), self不能算参数,所以只存在一个参数

	PyObject* cons_args = PyTuple_New(1);	
	PyObject* cons_arg1 = PyLong_FromLong(100);	
	PyTuple_SetItem(cons_args, 0, cons_arg1);


	// 构造Person的实例
	PyObject* pInstancePerson = PyObject_CallObject(pClasspPerson, cons_args);
	if (!pInstancePerson)
	{
		printf("Cant find calc instance.\n");
		return -1;
	}

	//【4】调用类中的方法
	// 调用类方法 - WhatEat
	PyObject *WhatEatreturn = PyObject_CallMethod(pInstancePerson, "WhatEat", "", "");
	if (!WhatEatreturn)
	{
		printf("不能找到 WhatEat 方法!");
		return -1;
	}

	// 调用类方法 - EatThis   函数EatThis(self,foodName)的参数含有两个,self可省略
	PyObject *EatThisReturn = PyObject_CallMethod(pInstancePerson, "EatThis", "(s)", "rice");
	if (!EatThisReturn)
	{
		printf("不能找到 EatThis 方法!");
		return -1;
	}

	// 调用类方法 - GetEat
	PyObject *GetEatReturn = PyObject_CallMethod(pInstancePerson, "GetEat", "", "");
	if (!GetEatReturn)
	{
		printf("不能找到 GetEatReturn 方法!");
		return -1;
	}
	char *GetEatBuf = nullptr;
	PyArg_Parse(GetEatReturn, "s", &GetEatBuf);								//转换返回类型
	std::cout << "Person GetEat: " << GetEatBuf << endl;
	GetEatBuf = nullptr;

	// 调用类方法 - GetAge
	PyObject *GetAgeReturn = PyObject_CallMethod(pInstancePerson, "GetAge", "", "");
	if (!GetAgeReturn)
	{
		printf("不能找到 GetAgeReturn 方法!");
		return -1;
	}
	int GetAgeValue;
	PyArg_Parse(GetAgeReturn, "i", &GetAgeValue);	//转换返回类型
	std::cout << "Person GetAge: " << GetAgeValue << endl;
	Py_Finalize();	//调用Py_Finalize,这个根Py_Initialize相对应的。

}

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第9张图片

【4】含有第三方库的代码展示

以c++调用python模块中torch模块为例

【4.1】python代码

#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   test2.py
@Time    :   2021/04/15 09:43:36
@Author  :   Jian Song 
@Contact :   [email protected]
@Desc    :   None
'''

# here put the import lib
import sys
import torch

def usetorch():    
    x = torch.ones(5,3)
    print(x)


# if __name__=="__main__":
#     usetorch()

【4.2】c++代码

#include "pch.h"
#include 
#include 
#include   
#include 

using namespace std;

/*

	参考文献:
     (四)c/c++、python混合编程——c/c++调用python第三方包numpy等
	 https://blog.csdn.net/hao5335156/article/details/79515480

	 本例程是c++调用python中的torch模块

*/
wchar_t *GetWC(const char *c)
{
	const size_t cSize = strlen(c) + 1;
	wchar_t* wc = new wchar_t[cSize];
	mbstowcs(wc, c, cSize);

	return wc;
}

int main(int argc, char* argv[])
{

	//【1】初始化python
	Py_SetPythonHome(GetWC("G:/Anaconda3/envs/tensorflow/"));//python解释器所在路径,此处是创建的tensorflow环境中python编辑器
	Py_Initialize();
	PyRun_SimpleString("import sys");
	PyRun_SimpleString("sys.path.append('./')");//定位到脚本所在目录

	//直接运行python代码
	PyRun_SimpleString("print('python start')");
	//【2】引入模块
	PyObject *pModule = PyImport_ImportModule("test3");
	if (!pModule)
	{
		cout << "Import Module Failed" << endl;
		system("pause");
		return 0;
	}	   
	//【3】调用函数
	PyObject * pFunc1 = NULL;// 声明变量
	pFunc1 = PyObject_GetAttrString(pModule, "usetorch");//这里是要调用的函数名
	PyObject* pRet1 = PyObject_CallObject(pFunc1, nullptr);//调用函数

	//释放python
	Py_Finalize();
	system("pause");
	return 0;
}

参考文献:(四)c/c++、python混合编程——c/c++调用python第三方包numpy等

【5】相关技术解读

【5.1 】格式转换

【4】详述C++调用python脚本文件的类、成员函数、非成员函数及含第三方库的文件_第10张图片

s (string) [char *]
 
Convert a null-terminated C string to a Python object. If the C string pointer is NULL, None is used.
 
s# (string) [char *, int]
 
Convert a C string and its length to a Python object. If the C string pointer is NULL, the length is ignored and None is returned.
 
z (string or None) [char *]
 
Same as s.
 
z# (string or None) [char *, int]
 
Same as s#.
 
u (Unicode string) [Py_UNICODE *]
 
Convert a null-terminated buffer of Unicode (UCS-2 or UCS-4) data to a Python Unicode object. If the Unicode buffer pointer is NULL, Noneis returned.
 
u# (Unicode string) [Py_UNICODE *, int]
 
Convert a Unicode (UCS-2 or UCS-4) data buffer and its length to a Python Unicode object. If the Unicode buffer pointer is NULL, the length is ignored and None is returned.
 
i (integer) [int]
 
Convert a plain C int to a Python integer object.
 
b (integer) [char]
 
Convert a plain C char to a Python integer object.
 
h (integer) [short int]
 
Convert a plain C short int to a Python integer object.
 
l (integer) [long int]
 
Convert a C long int to a Python integer object.
 
B (integer) [unsigned char]
 
Convert a C unsigned char to a Python integer object.
 
H (integer) [unsigned short int]
 
Convert a C unsigned short int to a Python integer object.
 
I (integer/long) [unsigned int]
 
Convert a C unsigned int to a Python integer object or a Python long integer object, if it is larger than sys.maxint.
 
k (integer/long) [unsigned long]
 
Convert a C unsigned long to a Python integer object or a Python long integer object, if it is larger than sys.maxint.
 
L (long) [PY_LONG_LONG]
 
Convert a C long long to a Python long integer object. Only available on platforms that support long long.
 
K (long) [unsigned PY_LONG_LONG]
 
Convert a C unsigned long long to a Python long integer object. Only available on platforms that support unsigned long long.
 
n (int) [Py_ssize_t]
 
Convert a C Py_ssize_t to a Python integer or long integer.
 
New in version 2.5.
 
c (string of length 1) [char]
 
Convert a C int representing a character to a Python string of length 1.
 
d (float) [double]
 
Convert a C double to a Python floating point number.
 
f (float) [float]
 
Same as d.
 
D (complex) [Py_complex *]
 
Convert a C Py_complex structure to a Python complex number.
 
O (object) [PyObject *]
 
Pass a Python object untouched (except for its reference count, which is incremented by one). If the object passed in is a NULL pointer, it is assumed that this was caused because the call producing the argument found an error and set an exception. Therefore, Py_BuildValue()will return NULL but won’t raise an exception. If no exception has been raised yet, SystemError is set.
 
S (object) [PyObject *]
 
Same as O.
 
N (object) [PyObject *]
 
Same as O, except it doesn’t increment the reference count on the object. Useful when the object is created by a call to an object constructor in the argument list.
 
O& (object) [converter, anything]
 
Convert anything to a Python object through a converter function. The function is called with anything (which should be compatible withvoid *) as its argument and should return a “new” Python object, or NULL if an error occurred.
 
(items) (tuple) [matching-items]
 
Convert a sequence of C values to a Python tuple with the same number of items.
 
[items] (list) [matching-items]
 
Convert a sequence of C values to a Python list with the same number of items.
 
{items} (dictionary) [matching-items]
 
Convert a sequence of C values to a Python dictionary. Each pair of consecutive C values adds one item to the dictionary, serving as key and value, respectively.
 
If there is an error in the format string, the SystemError exception is set and NULL returned.
 
Showing off sucks.

【5.2】函数简介

PyObject_CallMethod(pClass, “class_method”, “O”, pInstance) 
参数分别为 PyObject(类),string(类方法),string(O表示参数为PyObject) ,PyObject(类实例)

PyObject_CallFunction(pFun, “O”, pyores) 
参数分别为 PyObject(函数),string(O表示参数为PyObject) ,PyObject(函数中使用的参数)

 

参考文献:C++调用python

               PyObject_CallMethod

 

你可能感兴趣的:(混合编程)