在现代软件开发中性能C与灵活性Python的结合是许多大型项目的首选方案。无论是游戏引擎如 Unreal Engine还是高性能计算工具通过在 C 中嵌入 Python 脚本可以让用户在不重新编译程序的情况下编写插件或逻辑。本文将带你走进 Python C API 的世界重点介绍如何通过Py_Initialize实现 C 对 Python 的嵌入调用。为什么要嵌入 Python脚本化允许用户自定义逻辑。快速原型利用 Python 丰富的库如 NumPy, SciPy处理数据而核心逻辑保持在 C 中。逻辑分离将频繁变动的业务逻辑放在脚本层核心底层放在 C 层。核心流程图在深入代码之前我们先看下 C 调用 Python 的标准生命周期第一步环境配置要在 C 中使用 Python API你需要头文件Python.h位于 Python 安装目录的include文件夹。库文件python3x.libWindows或libpython3x.soLinux。注意确保你的 C 编译位数x64/x86与 Python 安装版本一致否则会报链接错误。第二步最简实现Hello World我们先从最简单的初始化和运行一段 Python 代码开始。1234567891011121314151617181920#include Python.h#include iostreamintmain() {// 1. 初始化 Python 解释器Py_Initialize();if(!Py_IsInitialized()) {std::cerr Python 初始化失败 std::endl;return-1;}// 2. 执行简单的 Python 语句PyRun_SimpleString(print(Hello from Python! I am embedded in C.));PyRun_SimpleString(import platform; print(Python Version:, platform.python_version()));// 3. 释放资源Py_Finalize();return0;}第三步进阶——调用 Python 函数并传递参数在实际项目中我们通常需要加载一个.py文件并调用其中的特定函数。1. 准备 Python 脚本 (script.py)1234# script.pydefadd(a, b):print(fPython 收到参数: {a} 和 {b})returnab2. C 调用代码调用过程涉及 Python 对象的引用计数管理这是最容易出错的地方。12345678910111213141516171819202122232425262728293031323334353637#include Python.h#include iostreamintmain() {Py_Initialize();// 将当前路径加入 Python 的搜索路径否则找不到 script.pyPyRun_SimpleString(import sys; sys.path.append(.));// 加载模块PyObject* pModule PyImport_ImportModule(script);if(pModule) {// 获取函数对象PyObject* pFunc PyObject_GetAttrString(pModule,add);if(pFunc PyCallable_Check(pFunc)) {// 创建参数元组 (3, 5)PyObject* pArgs PyTuple_Pack(2, PyLong_FromLong(3), PyLong_FromLong(5));// 调用函数PyObject* pValue PyObject_CallObject(pFunc, pArgs);if(pValue) {std::cout C 收到结果: PyLong_AsLong(pValue) std::endl;Py_DECREF(pValue);}Py_DECREF(pArgs);}Py_XDECREF(pFunc);Py_DECREF(pModule);}else{PyErr_Print();// 打印 Python 错误堆栈}Py_Finalize();return0;}核心 API 详解函数功能Py_Initialize()启动 Python 解释器并加载基本模块。PyRun_SimpleString()执行单行 Python 代码简单快捷但无法获取返回值。PyImport_ImportModule()动态加载一个 .py 模块。PyObject_GetAttrString()从模块中获取属性如函数、类。PyTuple_Pack()将 C 数据打包成 Python 的元组用于函数传参。Py_DECREF()减少引用计数。极其重要否则会导致严重的内存泄漏。避坑指南经验总结路径问题Python 解释器默认不搜索 C 可执行文件目录。务必使用sys.path.append(.)或设置PYTHONPATH环境变量。Debug/Release 陷阱在 Windows 上如果你编译 C 为 Debug 模式它会尝试寻找python3x_d.lib。如果你的 Python 环境没有安装调试库请确保 C 使用 Release 模式或者手动修改宏定义。引用计数遵循“谁创建谁负责”的原则。如果你通过PyImport或PyObject_Get获得了对象不用时必须Py_DECREF。多线程 (GIL)如果你的 C 程序是多线程的且多个线程都要调用 Python你需要处理GIL (Global Interpreter Lock)。