C++环境配置
Windows下
以VS为例,配置包含目录和库目录
图1. 目录设置
编译平台(x64和win32)需要与Python版本一致
debug模式下需要将python27.lib重命名为python27_d.lib
Linux下
以QT为例,配置包含目录和库目录
// xxx.pro
INCLUDEPATH += -I /usr/include/python2.7/
LIBS += -L /usr/lib/python2.7/config-x86_64-linux-gnu/ -lpython2.7
调用示例
分别调用python函数和python类
1)Python 实现具体方法
假设脚本名字为 pyTest.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
def add_it(a, b):
print '[python] add %d and %d'%(a, b)
return a+b
class cladd:
def __init__(self, param1, param2):
print 'param1: ',param1
print 'param2: ',param2
def add_it(self, a, b):
print '[python-class] add %d and %d'%(a, b)
return a+b
2)C++直接调用 pyTest.py 的函数 add_it
#include "stdafx.h"
#include "iostream"
#include "Python.h"
using namespace std;
void main()
{
// 初始化
Py_Initialize();
// 加载模块
PyObject* moudleName = PyString_FromString("pyTest");
PyObject* pModule = PyImport_Import(moudleName);
if(!pModule){
cout << "Python get moudle failed" <
return;
}
cout << "Python get moudle succeed" <
// 加载函数
PyObject* pFunc = PyObject_GetAttrString(pModule, "add_it");
if(!pFunc || !PyCallable_Check(pFunc)){
cout << "can not find function"<
return;
}
cout << "get function succeed" <
// 设置参数
PyObject* args = PyTuple_New(2);
PyObject* arg1 = PyInt_FromLong(4);
PyObject* arg2 = PyInt_FromLong(3);
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
// 调用函数
PyObject* pRet = PyObject_CallObject(pFunc, args);
// 获取返回
if(pRet){
long result = PyInt_AsLong(pRet);
cout << "result: "<
}
// 释放资源
Py_Finalize();
}
3)C++ 调用 pyTest.py 的 cladd 类
void main()
{
// 初始化
Py_Initialize();
// 加载模块
PyObject* moudleName = PyString_FromString("pyTest");
PyObject* pModule = PyImport_Import(moudleName);
if(!pModule){
cout << "Python get moudle failed" <
return;
}
cout << "Python get moudle succeed" <
// 加载类
PyObject* pClass = PyObject_GetAttrString(pModule, "cladd");
if(!pClass){
cout << "can not find class"<
return;
}
cout << "get class succeed" <
// 创建类实例
PyObject* args = PyTuple_New(2);
PyObject* arg1 = Py_BuildValue("s", "da");
PyObject* arg2 = Py_BuildValue("s", "dada");
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
PyObject* pInstance = PyInstance_New(pClass, args, NULL);
// 调用方法
PyObject* pRet = PyObject_CallMethod(pInstance, "add_it", "(ii)", 4, 3);
// 获取返回
if(pRet){
long result = PyInt_AsLong(pRet);
cout << "result: "<
}
// 释放资源
Py_Finalize();
}
细节
所有Python元素在 C里都是 PyObject 对象
Python 类型 XXX 和 C 类型 YYY 的转换使用 PyXXX_AsYYY 和 PyXXX_FromYYY
基本流程是:
1)初始化 -> Py_Initialize()
2)加载模块 -> PyImport_Import(PyString_FromString(“python 脚本名”))
3)加载函数/类 -> PyObject_GetAttrString(…)
4)创建类实例 -> PyInstance_New(…)
5)设置参数
6)调用函数/方法 -> PyObject_CallObject(…) / PyObject_CallMethod(…)
7)解除对象引用(以便python垃圾回收) -> Py_DECREF(PyObject*)
8)释放资源 -> Py_Finalize()
设置参数:
Python的参数实际上是元组,因此传参实际就是构造一个合适的元组
1)使用 PyTuple_New 创建元组,并用 PyTuple_SetItem 设置元组值
PyObject* args = PyTuple_New(3);
PyObject* arg1 = Py_BuildValue("i", 100); // 整数参数
PyObject* arg2 = Py_BuildValue("f", 3.14); // 浮点数参数
PyObject* arg3 = Py_BuildValue("s", "hello"); // 字符串参数
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
PyTuple_SetItem(args, 2, arg3);
2)直接使用 Py_BuildValue 构造元组
// (ifs)表示 int、float、string 3个值
PyObject* args = Py_BuildValue("(ifs)", 100, 3.14, "hello");
Python 脚本名称不要设为“test.py”,会出现错误,原因未知
Linux下 C 代码里还需指定 Python 脚本的路径,否则会找不到模块(windows下会默认在工程目录下找)
...
Py_Initialize(); // 初始化
// 指定 python 脚本的目录
string path = string("sys.path.append(\'/home/path-to-python-file\')");
const char* cstr_cmd = path .c_str();
PyRun_SimpleString("import sys");
PyRun_SimpleString(cstr_cmd);
// 加载模块
...