根本原因是Python解释器运行时环境未正确初始化:未调用Py_SetPythonHome()设置安装路径、未正确处理GIL(如PyEval_InitThreads)、或动态库加载失败,导致PyRun_SimpleString等函数因内存/锁/路径问题触发段错误。

为什么直接用 Py_Initialize() 会崩溃或失败
很多初学者调用 Py_Initialize() 后,一执行 PyRun_SimpleString("print('hello')") 就 segmentation fault,根本原因不是代码写错了,而是 Python 解释器没正确初始化运行时环境。C++ 程序启动时,Python 的全局解释器锁(GIL)、内存管理器、内置模块路径都没准备好。
关键点有三个:
-
Py_SetPythonHome()必须在Py_Initialize()前调用,且路径要指向实际的 Python 安装根目录(如/usr或C:\Python311),不能是空字符串或相对路径 - 必须显式调用
PyEval_InitThreads()(Python ≤ 3.6)或确保主线程已持有 GIL(Python ≥ 3.7),否则多线程调用PyRun类函数会崩 - Windows 下若链接的是
python311.lib(静态导入库),但运行时找不到python311.dll,会静默失败——建议用LoadLibrary手动加载并检查返回值
怎么把 C++ 对象安全暴露给 Python 而不泄漏内存
用 PyCapsule_New() 包裹原始指针是最轻量、最可控的方式,比 Boost.Python 或 pybind11 更底层但也更易出错。核心原则是:Python 拿到的必须是“可被 Python 生命周期管理”的对象。
典型错误是直接 return PyLong_FromVoidPtr(new MyClass)——Python 不知道怎么析构它,下次 GC 时就悬垂。
正确做法:
- 用
PyCapsule_New(ptr, "MyClass", [](PyObject* cap) { delete static_cast绑定析构回调(PyCapsule_GetPointer(cap, "MyClass")); }) - 在 Python 端用
ctypes.cast(ctypes.py_object(obj), ctypes.py_object).value取不到原生指针;必须用PyCapsule_GetPointer配合 C 扩展函数中转 - 如果 C++ 对象依赖 RAII(比如持有文件句柄),务必在 Capsule 的 destructor 回调里完整释放,不能只 delete 内存
Python 函数怎么传进 C++ 并同步/异步调用
Python 函数本质是 PyObject*,能存、能传、能 call,但调用前必须确认类型和参数匹配,否则 PyErr_Occurred() 会返回非空,但 C++ 不会自动抛异常——你得手动检查。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
常见陷阱:
- 用
PyObject_CallObject(func, args)时,args必须是 tuple;传单个参数得写PyTuple_Pack(1, arg),不是PyTuple_New(1)后再 setitem(容易漏 refcount) - 若 Python 函数可能触发异常(比如 raise ValueError),调用后必须立即检查:
if (PyErr_Occurred()) { PyErr_Print(); return; },否则后续任何 Python C API 调用都会失败 - 跨线程调用 Python 函数?先用
PyThreadState_Swap切换到对应线程的PyThreadState*,且全程持有 GIL(PyGILState_Ensure()/Release)
字符编码与字符串双向转换最容易丢数据
C++ 的 std::string 默认是字节序列,Python 3 的 str 是 Unicode。直接用 PyUnicode_FromString 传 UTF-8 编码的字符串没问题,但传含中文的本地编码(如 Windows CP936)就会解码失败,返回 NULL。
稳妥方案只有两条路:
- 强制统一用 UTF-8:C++ 侧所有字符串走
std::u8string或std::string+ UTF-8 编码,Python 侧用PyUnicode_FromUTF8和PyUnicode_AsUTF8 - 需要兼容系统 locale?用
PyUnicode_DecodeLocale(输入 bytes)和PyUnicode_AsEncodedString(输出 bytes),并指定 encoding 名,例如"gbk",但注意后者返回新引用,必须Py_DECREF - 绝对不要用
PyString_*系列函数(Python 3 已移除),编译都过不了
嵌入解释器不是加个头文件、连个库就完事的事。最常卡住的地方,其实是 Python 运行时路径、GIL 管理时机、以及字符串编码隐式转换这三处——它们不出错则一切顺利,一出错就毫无提示地崩掉或返回空指针。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










