必须设置Python路径后再调用Py_Initialize,否则易报ImportError或崩溃;需用Py_SetPythonHome和Py_SetPath指定根目录及模块路径,跨平台注意分隔符与权限。

用 Py_Initialize 启动 Python 解释器前必须设好路径
不设路径直接调用 Py_Initialize,大概率遇到 ImportError: No module named site 或脚本里 import numpy 直接崩溃。Python C API 启动时默认按系统路径找 site-packages 和标准库,而嵌入场景下它根本不知道你的 Python 安装在哪。
实操建议:
- 调用
Py_SetPythonHome指向 Python 安装根目录(比如/usr或C:Python39),不是python.exe所在目录 - 用
Py_SetPath显式传入sys.path内容,例如拼接home + "/lib/python3.9"和home + "/lib/python3.9/site-packages" - Windows 下注意路径分隔符用
\或正斜杠,避免字符串转义出错;Linux/macOS 要确认权限,别让解释器卡在读不到encodings包
执行 Python 脚本得用 PyRun_SimpleFileEx,别用 system()
system("python script.py") 看似简单,但没法捕获输出、无法传参、不能复用已初始化的解释器状态,还可能因环境变量或 Python 版本错乱失败。
实操建议:
- 用
fopen打开脚本文件后,传给PyRun_SimpleFileEx(fp, filename, closeit),closeit=1让 Python 自己关文件 - 如果要传命令行参数(类似
python script.py arg1 arg2),得先调PySys_SetArgv,且参数必须是wchar_t*数组(Linux/macOS 用mbstowcs转,Windows 可直接用GetCommandLineW) - 脚本里用
sys.argv拿参数,和终端运行行为一致
从 C++ 读取 Python 函数返回值,绕不开 PyObject* 类型转换
Python 函数返回的是通用指针 PyObject*,不转就只能打印地址。常见错误是直接强转成 int 或 char*,结果段错误或乱码。
实操建议:
- 用
PyLong_AsLong转整数,PyFloat_AsDouble转浮点,PyUnicode_AsUTF8转字符串(注意返回值可能为NULL,要检查) - 字符串转换后得到的是
const char*,别直接存指针——Python 对象一释放,内存就失效;需要复制到 C++std::string里 - 调用完记得用
Py_DECREF释放返回对象引用,否则内存泄漏;用Py_INCREF保活再传给别的函数也得配对
多线程调用 Python 必须管理 GIL,否则卡死或崩溃
Python 解释器全局锁(GIL)默认只允许一个线程执行 Python 字节码。C++ 主线程调了 Py_Initialize,子线程直接调 PyRun_SimpleString 会挂住或报 PyThreadState_Get: no current thread。
实操建议:
- 每个新线程首次调 Python API 前,必须调
PyThreadState_New创建线程状态,并用PyThreadState_Swap切换进去 - 进入 Python 执行前加
PyGILState_Ensure,退出后立刻PyGILState_Release;这对短任务最稳妥 - 如果 C++ 线程大部分时间在做计算、只偶尔调 Python,别一直占着 GIL——用
Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS把耗时 C++ 运算包起来,让其他 Python 线程能跑
跨语言交互最难的不是语法,是两边生命周期和资源归属没对齐。Python 对象谁 DECREF、GIL 在哪拿哪放、路径和编码怎么统一——这些地方松一扣,程序就飘在半空里,看不出错,但就是不按你想的走。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











