一、使用python提供给C/C++的API
1. 包含头文件
#include "Python.h"
注:因为python可能定义一些影响某些系统标准头的预处理器定义,所以必需在包含标准头文件(<stdio.h>, <string.h>, <errno.h>, <limits.h>, <assert.h> and <stdlib.h>)之前包含Python.h。
2.API介绍
以下是一些API的介绍:
void Py_Initialize(void)
初始化Python解释器,如果初始化失败,继续下面的调用会出现各种错误,可惜的是此函数没有返回值来判断是否初始化成功,如果失败会导致致命错误。
int Py_IsInitialized(void)
检查是否已经进行了初始化,如果返回0,表示没有进行过初始化。
void Py_Finalize()
反初始化Python解释器,包括子解释器,调用此函数同时会释放Python解释器所占用的资源。
int PyRun_SimpleString(const char *command)
实际上是一个宏,执行一段Python代码。
PyObject* PyImport_ImportModule(char *name)
导入一个Python模块,参数name可以是*.py文件的文件名。类似Python内建函数import。
PyObject* PyModule_GetDict( PyObject *module)
相当于Python模块对象的dict属性,得到模块名称空间下的字典对象。
PyObject* PyRun_String(const char* str, int start,PyObject* globals, PyObject* locals)
执行一段Python代码。
int PyArg_Parse(PyObject* args, char* format, …)
把Python数据类型解析为C的类型,这样C程序中才可以使用Python里面的数据。
PyObject* PyObject_GetAttrString(PyObject *o, char*attr_name)
返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name。
PyObject* Py_BuildValue(char* format, …)
和PyArg_Parse刚好相反,构建一个参数列表,把C类型转换为Python对象,使得Python里面可以使用C类型数据。
PyObject* PyEval_CallObject(PyObject* pfunc, PyObject*pargs)
此函数有两个参数,而且都是Python对象指针,其中pfunc是要调用的Python 函数,一般说来可以使用PyObject_GetAttrString()获得,pargs是函数的参数列表,通常是使用Py_BuildValue()来构建。
二、C++ 向 Python 传递参数
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构造元组
PyObject* args = Py_BuildValue("(ifs)", 100, 3.14, "hello");
PyObject* args = Py_BuildValue("()"); // 无参函数
三、PyArg_ParseTuple函数
作用:此函数其实相当于sscanf(str,format,…),是Py_BuildValue的逆过程,这个函数将PyObject参数转换成C/C++数据类型,传递的是指针,但这个函数与Py_BuildValue有点不同,这个函数只能解析Tuple元组,而Py_BuildValue函数可以生成元组,列表,字典等。
原型:PyAPI_FUNC(int) PyArg_ParseTuple(PyObject *args, const char *format,...)
Args:一般为Python程序返回的元组。
Foramt:与Py_BulidValue类型,就不在累述咯
四、 Py_BuildValue()函数
PyObject* Py_BuildValue(char* format, …)
参数解释:format及转换格式,类似与C语言中%d,%f,后面的不定参数对应前面的格式,具体格式如下:
"s"(string) [char *] :将C字符串转换成Python对象,如果C字符串为空,返回NONE。
"s#"(string) [char *, int] :将C字符串和它的长度转换成Python对象,如果C字符串为空指针,长度忽略,返回NONE。
"z"(string or None) [char *] :作用同"s"。
"z#" (stringor None) [char *, int] :作用同"s#"。
"i"(integer) [int] :将一个C类型的int转换成Python int对象。
"b"(integer) [char] :作用同"i"。
"h"(integer) [short int] :作用同"i"。
"l"(integer) [long int] :将C类型的long转换成Pyhon中的int对象。
"c"(string of length 1) [char] :将C类型的char转换成长度为1的Python字符串对象。
"d"(float) [double] :将C类型的double转换成python中的浮点型对象。
"f"(float) [float] :作用同"d"。
"O&"(object) [converter, anything] :将任何数据类型通过转换函数转换成Python对象,这些数据作为转换函数的参数被调用并且返回一个新的Python对象,如果发生错误返回NULL。
"(items)"(tuple) [matching-items] :将一系列的C值转换成Python元组。
"[items]"(list) [matching-items] :将一系列的C值转换成Python列表。
"{items}"(dictionary) [matching-items] :将一系类的C值转换成Python的字典,每一对连续的C值将转换成一个键值对。
举例:
后面为PyObject的返回值
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}
Py_BuildValue("((ii)(ii))(ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6))
五、元组操作函数:
因为程序之间传递的参数,大多数为Tuple类型,所以有专门的函数来操作元组:
PyAPI_FUNC(PyObject *)PyTuple_New(Py_ssize_t size);
解释:新建一个参数列表(调试了下,发现其实是用链表实现的),size列表为长度的宽度
PyAPI_FUNC(Py_ssize_t)PyTuple_Size(PyObject *);
解释:获取该列表的大小
PyAPI_FUNC(PyObject *)PyTuple_GetItem(PyObject *, Py_ssize_t);
解释:获取该列表某位置的值
PyAPI_FUNC(int) PyTuple_SetItem(PyObject *,Py_ssize_t, PyObject *);
解释:设置该列表此位置的值。如PyTuple_SetItem(pyParams,1,Py_BuildValue("i",2));设置第2个位置的值为2的整数。
方法一:主流方法将python程序编程文本形式的动态链接库,在c/c++程序中调用其中定义的函数
1. 链接到Python调用库
Python 安装目录下已经包含头文件( include 目录)和库文件 ( Windows 下为 python27.lib)。
使用之前需要链接到此库。
2. 直接调用 Python 语句
#include "python/Python.h"
int main()
{
Py_Initialize(); ## 初始化
PyRun_SimpleString("print 'hello'");
Py_Finalize(); ## 释放资源
}
3. 加载 Python 模块并调用函数
test.py :
def test_add(a, b):
print 'add ', a, ' and ', b
return a+b
#include "python/Python.h"
#include <iostream>
using namespace std;
int main()
{
Py_Initialize(); // 初始化
// 将Python工作路径切换到待调用模块所在目录,一定要保证路径名的正确性
string path = "~/test";
string chdir_cmd = string("sys.path.append(\"") + path + "\")";
const char* cstr_cmd = chdir_cmd.c_str();
PyRun_SimpleString("import sys");
PyRun_SimpleString(cstr_cmd);
// 加载模块
PyObject* moduleName = PyString_FromString("test"); //模块名,不是文件名
PyObject* pModule = PyImport_Import(moduleName);
if (!pModule) // 加载模块失败
{
cout << "[ERROR] Python get module failed." << endl;
return 0;
}
cout << "[INFO] Python get module succeed." << endl;
// 加载函数
PyObject* pv = PyObject_GetAttrString(pModule, "test_add");
if (!pv || !PyCallable_Check(pv)) // 验证是否加载成功
{
cout << "[ERROR] Can't find funftion (test_add)" << endl;
return 0;
}
cout << "[INFO] Get function (test_add) succeed." << endl;
// 设置参数
PyObject* args = PyTuple_New(2); // 2个参数
PyObject* arg1 = PyInt_FromLong(4); // 参数一设为4
PyObject* arg2 = PyInt_FromLong(3); // 参数二设为3
PyTuple_SetItem(args, 0, arg1);
PyTuple_SetItem(args, 1, arg2);
// 调用函数
PyObject* pRet = PyObject_CallObject(pv, args);
// 获取参数
if (pRet) // 验证是否调用成功
{
long result = PyInt_AsLong(pRet);
cout << "result:" << result;
}
Py_Finalize(); ## 释放资源
return 0;
}
方法二:完整调用python脚本文件及参数的方法。
以下是测试用的python脚本文件,功能是输出命令行参数:sample.py
# !/usr/bin/env python2.6
import sys
def test():
for arg in sys.argv:
print arg
if __name__=='__main__':
test()
以下是测试用的c程序文件:test.c
#include "python2.6/Python.h"
int main()
{
//第一步:初始化Python
//在调用Python的提供的给C的API之前,通过执行初始化
//来添加Python的内建模块、__main__、sys等
Py_Initialize();
//检查初始化是否完成
if (!Py_IsInitialized())
{
return -1;
}
//第二步:导入sys模块
PyRun_SimpleString("import sys");
//第三步:导入执行脚本时的命令行参数,如:./sample.py int argc = 2;
char *argv[2];
argv[0] = "arg1";
argv[1] = "arg2";
PySys_SetArgv(argc, argv);
//第四步:执行调用脚本文件命令,注意文件的路径
if (PyRun_SimpleString("execfile('./sample.py')") == NULL)
{
return -1;
}
//第五步:关闭Python解释器
Py_Finalize();
return 0;
}
编译指令:
g++ -g -W -o test test.cpp -I /usr/include/ -L /usr/lib64/ -l python2.
执行指令:./test
输出:
arg1
arg2