Python调用C/C++函数(2017-12-23)
1、已有资料整理
(1)封装步骤介绍:https://www.cnblogs.com/dchipnau/p/5296728.html
(2)数据类型对照:https://www.cnblogs.com/btchenguang/archive/2012/09/04/2670849.html
(3)C++调用Python类型:https://www.ibm.com/developerworks/cn/linux/l-pythc/
(4)Python官网文档:https://docs.python.org/2.7/c-api/list.html
2、编程步骤如下:
(1)基本要求:
A、VS2015编译器:
B、Python2.7以上:
(2)c++文档:glmgen.cpp
#include "C:\\anaconda2\\include\Python.h"
#pragma comment(lib, "C:\\anaconda2\\libs\\python27.lib")
#include<string.h>
#include<stdlib.h>
#include "utils.h"
##include <math.h>
//原始函数(一):glmgen_factorial
double glmgen_factorial(int n)
{
int i = 0;
double x = 1;
for (i = 2; i <= n; i++) {
x *= i;
}
return x;
}
//原始函数(二):l1norm
double l1norm(double * x, int n) {
int i;
double s;
s = 0;
for (i = 0; i < n; i++)
{
s += fabs(x[i]);
}
return s;
}
//封装一:数据类型转换
#ifdef __cplusplus
extern "C" {
#endif
PyObject* glmgen_glmgen_factorial(PyObject* self, PyObject* args)
{
int n, result;
if (!PyArg_ParseTuple(args, "i", &n))
return NULL;
result = glmgen_factorial(n);
return Py_BuildValue("i", result);
}
PyObject* glmgen_l1norm(PyObject* self, PyObject* args)
{
int i, n;
double x[3], result;
char* y;
char* pch;
//返回的是list:
PyObject* pList = PyList_New(3);
assert(PyList_Check(pList));
//返回的是dict:
PyObject* pDict = PyDict_New();
assert(PyDict_Check(pDict));
if (!PyArg_ParseTuple(args, "si", &y, &n))
return NULL;
i = 0;
pch = strtok(strdup(y), ",");
while (pch != NULL)
{
x[i] = atof(pch);
pch = strtok(NULL, ",");
PyList_SetItem(pList, i, Py_BuildValue("d", x[i]));
i++;
}
PyDict_SetItemString(pDict, "x_data", pList);
PyDict_SetItemString(pDict, "l1norm_data", Py_BuildValue("d", result = l1norm(&x, n)));
return pDict;
Py_DECREF(pList);
Py_DECREF(pDict);
}
//函数数组
static PyMethodDef glmgenMethods[] =
{
{ "glmgen_factorial", glmgen_glmgen_factorial, METH_VARARGS, "Caculate N!" },
{ "l1norm", glmgen_l1norm, METH_VARARGS, "Caculate l1norm" },
{ NULL, NULL }
};
//函数初始化
__declspec(dllexport) void initglmgen()
{
PyObject* m;
m = Py_InitModule("glmgen", glmgenMethods);
}
#ifdef __cplusplus
}
#endif
注意:
A、代码块
#ifdef __cplusplus
extern "C" {
#endif
/*
something need to calculates
*/
#ifdef __cplusplus
}
#endif
这是必须要的,解决c++编译c出现的问题。
B、由于Pyhton本身是C语言编译的,二者互调时,相当于c++里面的指针变量都指向Python传入的数据,一旦在C++中改变,原始数据也会变化,因此,需要返回原始数据时,需要复制原始数据(使用函数strdup(y))。
C、返回类型为C++类型时,需要在函数返回类型前加__declspec(dllexport) 。
D、声明的动态变量、中间变量、存储返回变量记得释放内存:Py_DECREF(pList)。
E、传入整数(double、string、char、char *),可以直接使用 PyArg_ParseTuple(args, "si", &y, &n)、Py_BuildValue("d", x[i]);当使用列表、字典、元组等Python类型时,需要在Python中转化为字符串,以字符串形式传入C++,然后在C++中转为C++类型。本办法虽笨,但很实用。对于传回Python的,无需做相应转化,只要在Python中使用相应方法即可,具体参见引文(3)、(4)。
最后将上述代码编译为:glmgen.pyd(即为glmgen.dll)
3、Python代码
from glmgen import *
#----将列表转化为字符串
def list2str(list_data):
return ','.join([str(i)for i in list_data])
#调用C++函数
x= glmgen_factorial(8)
ls1= [1,2,3]
ls2= util.list2str(ls1)
t= l1norm(ls2,3)
print ls2,t
输出:
1,2,3 {'x_data': [1.0, 2.0, 3.0], 'l1norm_data': 6.0}
!!!大功告成!!!