一:调用流程
1:必须首先调用Py_Initialize(),初始化python运行所需模块。
2:接着调用Py_IsInitialized(),检查初始化是否成功
3:调用PyRun_SimpleString(),引入常用的路径
4:调用Pyimport_importModule(),加载python模块,引入py文件
5:调用PyModule_GetDict(),获取模块字典
6:调用PyObject_GetAttrString() PyDict_GetItemString(),获取相应的方法或者类
7:调用Pyeval_CallObject() PyObject_CallMethod() 调用相应的方法
8:调用Py_DECREF() 释放python api创建的对象
9:调用Py_Finalize() 释放python模块
二:实例
1:调用py文件中的普通方法
Py_Initialize();
if (!Py_IsInitialized())
{
printf("python初始化失败!");
return 0;
}
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
pModule = Pyimport_importModule("test_cpp_call_py");
assert(pModule != NULL);
PyObject *pFuncHello = PyObject_GetAttrString(pModule, "Hello");
PyObject *pArgHello = Py_BuildValue("(s)", "Hello Charity");
PyObject *resultHello = Pyeval_CallObject(pFuncHello, pArgHello);
char *hello = NULL;
PyArg_Parse(resultHello,"s",&hello);
printf("call Hello result=%sn", hello);
pDict = PyModule_GetDict(pModule);
assert(pDict != NULL);
PyObject* pFuncAdd = PyDict_GetItemString(pDict, "Add");
PyObject* pArgAdd = Py_BuildValue("(i, i)", 1, 2);
PyObject *resultAdd = Pyeval_CallObject(pFuncAdd, pArgAdd);
int c;
PyArg_Parse(resultAdd, "i", &c);
printf("call Add result=%dn", c);
上边代码展示了2种获取方法,一种是直接从pModule中通过PyObject_GetAttrString()根据方法名获取方法,另外一种是先从pModule中通过调用PyModule_GetDict获取pDict,然后在从pDict中通过调用PyDict_GetItemString(),同样是根据方法名获取方法。
2:调用py文件中的类,先获取类 再创建类对象
pClass = PyDict_GetItemString(pDict, "Person");
assert(pClass != NULL);
pInstance = PyObject_CallObject(pClass, NULL);
assert(pInstance != NULL);
pClass 就是类型从dic中获取的类,然后需要实例化才能调用实例方法
result = PyObject_CallMethod(pInstance, "getInfo", "");
PyObject_CallMethod(pInstance, "setInfo", "si", "tyl", 24);
result1 = PyObject_CallMethod(pInstance, "getInfo", "");
PyArg_ParseTuple(result, "si", &name, &age);
printf("result:%s-%dn", name, age);
PyArg_ParseTuple(result1, "si", &name, &age);
printf("result1:%s-%dn", name, age);
3:释放资源
Py_DECREF(pModule);
Py_DECREF(pDict);
Py_DECREF(pClass);
Py_DECREF(pInstance);
Py_DECREF(result);
Py_Finalize();
三:编译+测试
test_cpp_call_py.c
#includeint main(int argc,char **argv) { PyObject *pModule, *pDict, *pClass, *pInstance; PyObject *result, *result1; //初始化python Py_Initialize(); if (!Py_IsInitialized()) { printf("python初始化失败!"); return 0; } PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('./')"); pModule = Pyimport_importModule("test_cpp_call_py"); assert(pModule != NULL); PyObject *pFuncHello = PyObject_GetAttrString(pModule, "Hello"); PyObject *pArgHello = Py_BuildValue("(s)", "Hello Charity"); PyObject *resultHello = Pyeval_CallObject(pFuncHello, pArgHello); char *hello = NULL; PyArg_Parse(resultHello,"s",&hello); printf("call Hello result=%sn", hello); Py_DECREF(pFuncHello); Py_DECREF(pArgHello); Py_DECREF(resultHello); pDict = PyModule_GetDict(pModule); assert(pDict != NULL); PyObject* pFuncAdd = PyDict_GetItemString(pDict, "Add"); PyObject* pArgAdd = Py_BuildValue("(i, i)", 1, 2); PyObject *resultAdd = Pyeval_CallObject(pFuncAdd, pArgAdd); int c; PyArg_Parse(resultAdd, "i", &c); printf("call Add result=%dn", c); Py_DECREF(pFuncAdd); Py_DECREF(pArgAdd); Py_DECREF(resultAdd); //通过字典属性获取模块中的类 pClass = PyDict_GetItemString(pDict, "Person"); assert(pClass != NULL); pInstance = PyObject_CallObject(pClass, NULL); assert(pInstance != NULL); PyRun_SimpleString("print('-'*10, 'Python start', '-'*10)"); result = PyObject_CallMethod(pInstance, "getInfo", ""); PyObject_CallMethod(pInstance, "setInfo", "si", "tyl", 24); result1 = PyObject_CallMethod(pInstance, "getInfo", ""); char* name; int age; PyArg_ParseTuple(result, "si", &name, &age); printf("result:%s-%dn", name, age); PyArg_ParseTuple(result1, "si", &name, &age); printf("result1:%s-%dn", name, age); PyRun_SimpleString("print('-'*10, 'Python end', '-'*10)"); Py_DECREF(result); Py_DECREF(result1); Py_DECREF(pModule); Py_DECREF(pDict); Py_DECREF(pClass); Py_DECREF(pInstance); PyRun_SimpleString("print('-'*10, 'decref end', '-'*10)"); Py_Finalize(); }
test_cpp_call_py.py
#coding:utf-8
'''
create on 2017-04-20
@author:sandy
'''
def Hello(s):
print ("Hello World")
print(s)
return s
def Add(a, b):
print('a=', a)
print ('b=', b)
return a + b
class Person(object):
def __init__(self):
self.name = "mandy"
self.age = 20
def setInfo(self,name,age):
print(self,dir(self),name)
self.name = name
self.age = age
def getInfo(self):
print('python: name={}, age={}'.format(self.name, self.age))
return self.name, self.age
def sayHello(self, name):
print(self,dir(self),name)
# self.name = "sssss"
print ("Hello,", name)
return name
由于本地有多个版本的Python,所以要指定python3.6m
gcc test_cpp_call_py.c -o nonu -lpython3.6m
另外:
看文档还有一种方法创建,但是这个pInstance 和 上边方式创建的pInstance 是不一样的,具体怎么一个不一样,我还没有研究透。。。
pInstance = PyInstanceMethod_New(pClass);
result = PyObject_CallMethod(pInstance, "sayHello", "(Os)", pInstance, "Charity");
char* name=NULL;
PyArg_Parse(result, "s", &name);
printf("call sayHello = %sn", name);
PyObject_CallMethod(pInstance, "setInfo", "(Osi)", pInstance, "mandy",20);
如果把sayHello里边的 self.name = "ssss" 注释打开 在运行 就会是如下结果了
昨天测试的时候还报了 instancemethod 没有 name 属性
具体为啥后边研究了再补上
附上:c++访问python3-实例化类的方法
c++访问python3-实例化类的方法_love_clc的专栏-CSDN博客



