使用C++调用Python模块(Linux)

使用Python调用C++库见:我的另一篇博客

工程配置

本文使用的项目构建工具为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脚本中的模块,一般需要经过如下几个步骤:

  1. 使用Py_Initialize()函数初始化Python解释器环境

  2. 添加.py脚本的路径,使用如下函数完成:

    // 添加.py的路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('脚本路径')");
    

    PyRun_SimpleString()函数也可以用来执行单条Python命令。

  3. 导入模块,使用PyImport_ImportModule('模块名')完成:

    PyObject* pModule = PyImport_ImportModule("模块名");
    
  4. 导入函数,使用PyObject_GetAttrString(模块指针, "函数名")来完成:

    PyObject* pFunc = PyObject_GetAttrString(pModule, "函数名");
    
  5. 构造函数的传入参数,要求以元组的形式传入,有两种方式进行构造,一种是使用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(<length>)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);
    
  6. 执行函数,使用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 ;
    }
    
  7. 结束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 <iostream>
#include <Python.h>

int main(int argc, char** argv){
    // 运行Python解释器
    Py_Initialize();
    
    // 添加.py的路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('<scripts_path>')");
	
    /**************************
    ********* add函数 **********
    **************************/
    
    // 导入模块
    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 ;
    }
	
    /**************************
    ****** helloworld函数 *****
    **************************/
    
	// 导入函数
    pFunc = PyObject_GetAttrString(pModule, "helloworld");
    // 构造传入参数
    PyObject* str = Py_BuildValue("(s)", "python");
    // 执行函数
    PyObject_CallObject(pFunc, str);    
    // 终止Python解释器
    Py_Finalize();  

}

运行结果:

11
result:11
hello python
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值