1.c++调用Python
Python脚本如下:
def printHelloWold():
print('hello world')
def add(a, b):
c = a+b
return c
C++代码如下:
#include <iostream>
#include "Python.h"
using namespace std;
// 简易版本
void method1()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyRun_SimpleString("import pytest");
PyRun_SimpleString("pytest.printHelloWold()");
Py_Finalize();
}
// 初级版本
void method2()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyObject *pModule = NULL;
PyObject *pFunc = NULL;
pModule = PyImport_ImportModule("pytest"); //Python文件名
pFunc = PyObject_GetAttrString(pModule, "printHelloWold"); //Python文件中的函数名
PyEval_CallObject(pFunc, NULL); //调用函数,NULL表示参数为空
Py_Finalize(); //Py_Finalize,和Py_Initialize相对应的.
}
// 带参数和返回值版本
void method3()
{
Py_Initialize();
PyRun_SimpleString("import sys");
PyRun_SimpleString("sys.path.append('./')");
PyObject *pModule = NULL;
PyObject *pFunc = NULL;
pModule = PyImport_ImportModule("pytest"); //Python文件名
pFunc = PyObject_GetAttrString(pModule, "add"); //Python文件中的函数名
//创建参数:
PyObject *pArgs = PyTuple_New(2); //函数调用的参数传递均是以元组的形式打包的,2表示参数个数
PyTuple_SetItem(pArgs, 0, Py_BuildValue("i", 6)); //0--序号,i表示创建int型变量
PyTuple_SetItem(pArgs, 1, Py_BuildValue("i", 8)); //1--序号
//返回值
PyObject *pReturn = NULL;
pReturn = PyEval_CallObject(pFunc, pArgs); //调用函数
//将返回值转换为int类型
int result;
PyArg_Parse(pReturn, "i", &result); //i表示转换成int型变量
cout << "6 + 8 = " << result << endl;
Py_Finalize();
}
int main()
{
// 简易版本
method1();
// 初级版本
method2();
// 带参数和返回值版本
method3();
return 0;
}
CMakeLists.txt内容如下:
cmake_minimum_required( VERSION 2.8 )
project ( code_test )
set( CMAKE_CXX_COMPILER "g++" )
set( CMAKE_BUILD_TYPE "Debug" )
set( CMAKE_CXX_FLAGS "-std=c++11 -O0" )
include_directories(
/usr/include/python3.6m
)
link_directories(
/usr/lib/x86_64-linux-gnu
)
add_executable( run_test test.cpp )
target_link_libraries(run_test
libpython3.6m.so
)
如果用gcc,则相当于:
g++ test.cpp -I /usr/include/python3.6m -L /usr/lib/x86_64-linux-gnu -lpython3.6m
输出如下:
hello world
hello world
6 + 8 = 14
参考:
https://blog.csdn.net/qq_34731182/article/details/103206083
2. python的C扩展调用,使用原生的python-C-Api
1、在文件第一行包含python调用扩展的头文件
#include <Python.h>
2、用原生C写好需要调用的函数
int add_one(int a){
return a + 1;
}
3、用python规定的调用方式,加一层C语言的包装,包装内容包括
a.定义一个新的静态函数,接受两个PyObject *参数,返回一个PyObject *值
b.解析第二个输入的PyObject *(通过PyArg_ParseTuple等方法),把python输入的变量变成C的变量
c.调用原生C函数
d.将调用返回的C变量,转换为PyObject*或其子类(通过PyLong_FromLong)等方法,并返回
static PyObject * py_add_one(PyObject *self, PyObject *args){
int num;
if (!PyArg_ParseTuple(args, "i", &num)) return NULL;
return PyLong_FromLong(add_one(num));
}
4、创建一个数组,来指明python可调用这个扩展的函数。
其中"add_one",代表编译后python调用时希望使用的函数名,
py_add_one,代表调用当前C代码中的哪个函数,
METH_VARARGS,代表函数的参数传递形式,主要包括位置参数和关键字参数两种,
关于这个变量具体参考https://docs.python.org/3/extending/extending.html的1.4节。
如果希望添加新的函数,则在最后的{NULL, NULL}之前按同样格式填写新的调用信息。
static PyMethodDef Methods[] = {
{"add_one", py_add_one, METH_VARARGS},
{NULL, NULL}
};
5、创建module的信息,包括了python调用时的模块名、可调用的函数集(就是上一步定义的Methods)等信息
static struct PyModuleDef cModule = {
PyModuleDef_HEAD_INIT,
"Test", /*module name*/
"", /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
Methods
};
6、module初始化
PyMODINIT_FUNC PyInit_Test(void){ return PyModule_Create(&cModule);}
7、写一个setup.py脚本,使用distutils包作为包构建安装的工具
from distutils.core import setup, Extension
module1 = Extension('Test', sources = ['add.c'])
setup (name = 'Test',
version = '1.0',
description = 'This is a demo package',
ext_modules = [module1])
8、调用setup.py,python3 setup.py build可以编译代码,python3 setup.py install可以编译代码并直接将包放入当前python环境的包的路径以供调用。
非常需要注意的是,python 3.5版本以后,windows平台下python的C/C++扩展不再支持gcc的编译,并强制要求使用msvc进行编译
所以python setup.py build编译出来的结果无法正常使用,需使用
python3 setup.py build --compiler msvc
当需要安装时,则
python3 setup.py build --compiler msvc install
关于此情况的参考:
https://stackoverflow.com/questions/16737260/how-to-tell-distutils-to-use-gcc
https://stackoverflow.com/questions/3297254/how-to-use-mingws-gcc-compiler-when-installing-python-package-using-pip
9、测试安装好的C扩展
import Test as t
x = 1
print(t.add_one(x))
附C文件完整代码
#include <Python.h>
int add_one(int a){
return a + 1;
}
static PyObject * py_add_one(PyObject *self, PyObject *args){
int num;
if (!PyArg_ParseTuple(args, "i", &num)) return NULL;
return PyLong_FromLong(add_one(num));
}
static PyMethodDef Methods[] = {
{"add_one", py_add_one, METH_VARARGS},
{NULL, NULL}
};
static struct PyModuleDef cModule = {
PyModuleDef_HEAD_INIT,
"Test", /*module name*/
"", /* module documentation, may be NULL */
-1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
Methods
};
PyMODINIT_FUNC PyInit_Test(void){ return PyModule_Create(&cModule);}
https://www.cnblogs.com/catnip/p/8329298.html