在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 与其他实现的比较
特性 | CPython | PyPy | Jython | IronPython |
---|---|---|---|---|
实现语言 | C | RPython | Java | C# |
JIT 编译 | 无 | 有 | 依赖 JVM | 依赖 CLR |
性能特点 | 中等 | 快(长时间运行) | Java 集成 | .NET 集成 |
GIL | 有 | 有 | 无 | 无 |
CPython 的主要特点
-
解释器核心:将 Python 代码编译为字节码,然后在虚拟机上执行
-
标准库:包含丰富的内置模块和功能
-
C API:提供与 C/C++ 的互操作性
-
垃圾回收:使用引用计数为主,分代回收为辅的垃圾回收机制
CPython 的内部结构
-
对象系统:所有 Python 对象都是 PyObject 结构体的扩展
-
字节码编译器:将 Python 源代码编译为字节码
-
解释器循环:执行字节码
-
内存管理:引用计数和垃圾回收
-
全局解释器锁(GIL):保护 Python 对象免受并发访问
实际应用
-
性能关键部分的优化:用 C 重写热点代码
-
集成现有 C 库:通过 Python 包装 C 库
-
嵌入式脚本:在 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 的基本用法,包括函数调用、类实例化和方法调用
关键点说明
内存管理:
每个
PyObject*
都需要正确管理引用计数使用
Py_DECREF
释放不再需要的对象错误处理:
检查每个 Python API 调用的返回值
使用
check_python_error
捕获 Python 异常类型转换:
C++ 到 Python:
PyLong_FromLong
,PyUnicode_FromString
Python 到 C++:
PyLong_AsLong
,PyUnicode_AsUTF8
模块路径:
确保 Python 可以找到你的模块 (通过
sys.path
)资源清理:
在程序退出前调用
Py_Finalize