C++调用Python

在C++中调用Python代码通常有两种主要方法:使用Python解释器作为外部进程,或者使用Python的C API。

方法1:使用Python解释器作为外部进程

这种方法通过C++调用系统的Python解释器来执行Python代码。这可以通过多种方式实现,例如使用system()函数、popen()函数或更高级的库如Boost.Process

///使用system()函数:
#include <cstdlib>
 
int main() {
    // 调用Python脚本
    system("python script.py");
    return 0;
}


///使用popen()函数:
#include <cstdio>
#include <iostream>
#include <string>
 
int main() {
    FILE* pipe = popen("python script.py", "r");
    if (!pipe) {
        return -1;
    }
    char buffer[128];
    std::string result = "";
    while (!feof(pipe)) {
        if (fgets(buffer, 128, pipe) != NULL) {
            result += buffer;
        }
    }
    pclose(pipe);
    std::cout << "Python output: " << result << std::endl;
    return 0;
}

方法2:使用Python的C API

这种方法涉及到在C++中直接调用Python的C API函数,这需要你了解并链接Python的库。这种方法通常用于性能敏感的应用,因为它避免了启动外部进程的开销。

#include <Python.h>
 
int main() {
    // 初始化Python解释器
    Py_Initialize();
 
    // 执行Python代码
    PyRun_SimpleString("print('Hello from Python')");
 
    // 清理并退出
    Py_Finalize();
    return 0;
}

CPython: Python 的参考实现

CPython 是 Python 编程语言的官方参考实现,用 C 语言编写。它是 Python 解释器的最常见形式,也是其他实现(如 PyPy、Jython、IronPython 等)的参考标准。

CPython 与其他实现的比较

特性CPythonPyPyJythonIronPython
实现语言CRPythonJavaC#
JIT 编译依赖 JVM依赖 CLR
性能特点中等快(长时间运行)Java 集成.NET 集成
GIL

CPython 的主要特点

  1. 解释器核心:将 Python 代码编译为字节码,然后在虚拟机上执行

  2. 标准库:包含丰富的内置模块和功能

  3. C API:提供与 C/C++ 的互操作性

  4. 垃圾回收:使用引用计数为主,分代回收为辅的垃圾回收机制

CPython 的内部结构

  1. 对象系统:所有 Python 对象都是 PyObject 结构体的扩展

  2. 字节码编译器:将 Python 源代码编译为字节码

  3. 解释器循环:执行字节码

  4. 内存管理:引用计数和垃圾回收

  5. 全局解释器锁(GIL):保护 Python 对象免受并发访问

实际应用

  1. 性能关键部分的优化:用 C 重写热点代码

  2. 集成现有 C 库:通过 Python 包装 C 库

  3. 嵌入式脚本:在 C/C++ 应用中嵌入 Python 脚本功能

CPython 的 C API 虽然强大,但也需要小心使用,特别是内存管理和错误处理方面,以避免内存泄漏和程序崩溃。

完整示例:

下面是一个完整的示例,展示如何在 C++ 程序中嵌入 Python 解释器,调用 Python 函数并处理返回值

1. 准备 Python 脚本 (example.py)

首先创建一个简单的 Python 模块:

# example.py
def add_numbers(a, b):
    """Add two numbers and return the result"""
    return a + b

def greet(name):
    """Return a greeting message"""
    return f"Hello, {name}!"

class Multiplier:
    def __init__(self, factor):
        self.factor = factor
    
    def multiply(self, x):
        return x * self.factor

2. C++ 程序 (main.cpp)

#include <Python.h>
#include <iostream>
#include <string>

void check_python_error() {
    if (PyErr_Occurred()) {
        PyErr_Print();
        exit(1);
    }
}

int main() {
    // 1. 初始化 Python 解释器
    Py_Initialize();
    
    // 2. 将当前目录添加到 Python 模块搜索路径
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append(\".\")");
    
    try {
        // 3. 导入 Python 模块
        PyObject* pModule = PyImport_ImportModule("example");
        check_python_error();
        if (!pModule) {
            throw std::runtime_error("Failed to import Python module");
        }
        
        // ========== 调用简单函数 ==========
        
        // 4. 获取 add_numbers 函数
        PyObject* pFunc = PyObject_GetAttrString(pModule, "add_numbers");
        check_python_error();
        if (!pFunc || !PyCallable_Check(pFunc)) {
            throw std::runtime_error("Cannot find function 'add_numbers'");
        }
        
        // 5. 准备参数并调用函数
        PyObject* pArgs = PyTuple_Pack(2, PyLong_FromLong(3), PyLong_FromLong(4));
        PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
        check_python_error();
        
        // 6. 处理返回值
        if (pValue) {
            long result = PyLong_AsLong(pValue);
            std::cout << "3 + 4 = " << result << std::endl;
            Py_DECREF(pValue);
        }
        Py_DECREF(pArgs);
        Py_DECREF(pFunc);
        
        // ========== 调用返回字符串的函数 ==========
        
        pFunc = PyObject_GetAttrString(pModule, "greet");
        check_python_error();
        if (!pFunc || !PyCallable_Check(pFunc)) {
            throw std::runtime_error("Cannot find function 'greet'");
        }
        
        pArgs = PyTuple_Pack(1, PyUnicode_FromString("World"));
        pValue = PyObject_CallObject(pFunc, pArgs);
        check_python_error();
        
        if (pValue) {
            const char* greeting = PyUnicode_AsUTF8(pValue);
            std::cout << greeting << std::endl;
            Py_DECREF(pValue);
        }
        Py_DECREF(pArgs);
        Py_DECREF(pFunc);
        
        // ========== 使用 Python 类 ==========
        
        // 7. 获取类引用
        PyObject* pClass = PyObject_GetAttrString(pModule, "Multiplier");
        check_python_error();
        if (!pClass) {
            throw std::runtime_error("Cannot find class 'Multiplier'");
        }
        
        // 8. 创建类实例
        PyObject* pInstance = PyObject_CallFunction(pClass, "i", 5);  // factor=5
        check_python_error();
        if (!pInstance) {
            throw std::runtime_error("Failed to create Multiplier instance");
        }
        
        // 9. 调用实例方法
        PyObject* pMethod = PyObject_GetAttrString(pInstance, "multiply");
        check_python_error();
        if (!pMethod || !PyCallable_Check(pMethod)) {
            throw std::runtime_error("Cannot find method 'multiply'");
        }
        
        pArgs = PyTuple_Pack(1, PyLong_FromLong(7));  // x=7
        pValue = PyObject_CallObject(pMethod, pArgs);
        check_python_error();
        
        if (pValue) {
            long result = PyLong_AsLong(pValue);
            std::cout << "5 * 7 = " << result << std::endl;
            Py_DECREF(pValue);
        }
        
        // 10. 清理
        Py_DECREF(pArgs);
        Py_DECREF(pMethod);
        Py_DECREF(pInstance);
        Py_DECREF(pClass);
        Py_DECREF(pModule);
        
    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << std::endl;
    }
    
    // 11. 关闭 Python 解释器
    Py_Finalize();
    return 0;
}

这个示例展示了 CPython C API 的基本用法,包括函数调用、类实例化和方法调用

关键点说明

  1. 内存管理

    • 每个 PyObject* 都需要正确管理引用计数

    • 使用 Py_DECREF 释放不再需要的对象

  2. 错误处理

    • 检查每个 Python API 调用的返回值

    • 使用 check_python_error 捕获 Python 异常

  3. 类型转换

    • C++ 到 Python: PyLong_FromLongPyUnicode_FromString

    • Python 到 C++: PyLong_AsLongPyUnicode_AsUTF8

  4. 模块路径

    • 确保 Python 可以找到你的模块 (通过 sys.path)

  5. 资源清理

    • 在程序退出前调用 Py_Finalize

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值