本文使用的项目构建工具为CMake,使用FindPython工具在CMake工程中找到Python库,注意CMake最低版本为3.12,参考:https://cmake.org/cmake/help/latest/module/FindPython.html
创建call_python.cpp文件,程序内容在下节详细说明。CMakeLists.txt文件如下:
cmake_minimum_required(VERSION 3.12)
project(CallPython)
find_package (Python COMPonENTS Interpreter Development)
message(STATUS "Python_VERSION: ${Python_INCLUDE_DIRS}")
include_directories(
${PROJECT_SOURCE_DIR}/include
${Python_INCLUDE_DIRS}
)
# 生成目标文件
add_executable(call_python src/call_python.cpp)
# 链接库
target_link_libraries(call_python ${Python_LIBRARIES})
调用方法
使用C++调用Python脚本中的模块,一般需要经过如下几个步骤:
-
使用Py_Initialize()函数初始化Python解释器环境
-
添加.py脚本的路径,使用如下函数完成:
// 添加.py的路径 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append('脚本路径')");PyRun_SimpleString()函数也可以用来执行单条Python命令。
-
导入模块,使用Pyimport_importModule('模块名')完成:
PyObject* pModule = Pyimport_importModule("模块名"); -
导入函数,使用PyObject_GetAttrString(模块指针, "函数名")来完成:
PyObject* pFunc = PyObject_GetAttrString(pModule, "函数名");
-
构造函数的传入参数,要求以元组的形式传入,有两种方式进行构造,一种是使用Py_BuildValue()函数直接构造元组,使用方法如下:
PyObject* args = Py_BuildValue("");其中()内可以指定参数格式,如下表所示:
格式 实际输入 Py_BuildValue("") None Py_BuildValue(“i”, 123) 123 Py_BuildValue(“iii”, 123, 456, 789) 123, 456, 789 Py_BuildValue(“f”, 123.456) 123.456 Py_BuildValue(“fff”, 123.1, 456.2, 789.3) (123.1, 456.2, 789.3) Py_BuildValue(“s”, “hello”) ‘hello’ Py_BuildValue(“(s)”, “hello”) (‘hello’,) Py_BuildValue(“ss”, “hello”, “world”) (‘hello’, ‘world’) Py_BuildValue("(i)", 123) (123,) Py_BuildValue("((ii)(ii)) (ii)", 1, 2, 3, 4, 5, 6) (((1, 2), (3, 4)), (5, 6)) Py_BuildValue("{s:i,s:i}", “abc”, 123, “def”, 456) {‘abc’: 123, ‘def’: 456} 注:实际输入中带()的格式才是元组形式,其余均不能直接作为参数传入到函数中。
另一种方式是使用PyTuple_New(
)和PyTuple_SetItem(参数指针, index, value)函数间接构造元组: PyObject* args = PyTuple_New(2); PyTuple_SetItem(args, 0, Py_BuildValue("s", "python")); PyTuple_SetItem(args, 1, Py_BuildValue("i", 123);其中Py_BuildValue()使用方法见上表。
如果传入参数是列表形式,则使用PyList_New()来构造一个列表,再将该列表加入到元组中即可
// 构造一个列表,并添加成员 PyObject* list = PyList_New(3); PyList_SetItem(list, 0, Py_BuildValue("i", 1)); PyList_SetItem(list, 1, Py_BuildValue("i", 10)); PyList_SetItem(list, 2, Py_BuildValue("i", 100)); // 构造一个元组,将list加入到参数列表 PyObject* args = PyTuple_New(1); PyTuple_SetItem(args, 0, list); -
执行函数,使用PyObject_CallObject(函数指针, 参数指针)完成:
PyObject_CallObject(pFunc, args);
如果有返回值,则使用如下程序获取返回值:
PyObject* pRet = PyObject_CallObject(pFunc, args); if (pRet) { long result = PyLong_AsLong(pRet); // 将返回值转换成long型 std::cout << "result:" << result << std::endl ; } -
结束Python解释器:
Py_Finalize();
创建一个.py文件,命名为calculator.py,内容如下:
def add(a, b):
print(a + b)
return a + b
def helloworld(s):
print("hello " + s)
现在我们要调用该脚本中的add函数和helloworld函数,C++程序如下:
#include#include int main(int argc, char** argv){ // 运行Python解释器 Py_Initialize(); // 添加.py的路径 PyRun_SimpleString("import sys"); PyRun_SimpleString("sys.path.append(' ')"); // 导入模块 PyObject* pModule = Pyimport_importModule("calculator"); // 导入要运行的函数 PyObject* pFunc = PyObject_GetAttrString(pModule, "add"); // 构造传入参数 PyObject* args = PyTuple_New(2); PyTuple_SetItem(args, 0, Py_BuildValue("i", 1)); PyTuple_SetItem(args, 1, Py_BuildValue("i", 10)); // 运行函数,并获取返回值 PyObject* pRet = PyObject_CallObject(pFunc, args); if (pRet) { long result = PyLong_AsLong(pRet); // 将返回值转换成long型 std::cout << "result:" << result << std::endl ; } // 导入函数 pFunc = PyObject_GetAttrString(pModule, "helloworld"); // 构造传入参数 PyObject* str = Py_BuildValue("(s)", "python"); // 执行函数 PyObject_CallObject(pFunc, str); // 终止Python解释器 Py_Finalize(); }
运行结果:
11 result:11 hello python



