C++通過 Py_Initialize實(shí)現(xiàn)對(duì)Python的嵌入調(diào)用
在現(xiàn)代軟件開發(fā)中,性能(C++)與靈活性(Python)的結(jié)合是許多大型項(xiàng)目的首選方案。無論是游戲引擎(如 Unreal Engine)還是高性能計(jì)算工具,通過在 C++ 中嵌入 Python 腳本,可以讓用戶在不重新編譯程序的情況下編寫插件或邏輯。
本文將帶你走進(jìn) Python C API 的世界,重點(diǎn)介紹如何通過 Py_Initialize 實(shí)現(xiàn) C++ 對(duì) Python 的嵌入調(diào)用。
為什么要嵌入 Python
- 腳本化:允許用戶自定義邏輯。
- 快速原型:利用 Python 豐富的庫(如 NumPy, SciPy)處理數(shù)據(jù),而核心邏輯保持在 C++ 中。
- 邏輯分離:將頻繁變動(dòng)的業(yè)務(wù)邏輯放在腳本層,核心底層放在 C++ 層。
核心流程圖
在深入代碼之前,我們先看下 C++ 調(diào)用 Python 的標(biāo)準(zhǔn)生命周期:
第一步:環(huán)境配置
要在 C++ 中使用 Python API,你需要:
頭文件:Python.h(位于 Python 安裝目錄的 include 文件夾)。
庫文件:python3x.lib(Windows)或 libpython3x.so(Linux)。
注意:確保你的 C++ 編譯位數(shù)(x64/x86)與 Python 安裝版本一致,否則會(huì)報(bào)鏈接錯(cuò)誤。
第二步:最簡(jiǎn)實(shí)現(xiàn):Hello World
我們先從最簡(jiǎn)單的初始化和運(yùn)行一段 Python 代碼開始。
#include <Python.h>
#include <iostream>
int main() {
// 1. 初始化 Python 解釋器
Py_Initialize();
if (!Py_IsInitialized()) {
std::cerr << "Python 初始化失??!" << std::endl;
return -1;
}
// 2. 執(zhí)行簡(jiǎn)單的 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();
return 0;
}第三步:進(jìn)階——調(diào)用 Python 函數(shù)并傳遞參數(shù)
在實(shí)際項(xiàng)目中,我們通常需要加載一個(gè) .py 文件,并調(diào)用其中的特定函數(shù)。
1. 準(zhǔn)備 Python 腳本 (script.py)
# script.py
def add(a, b):
print(f"Python 收到參數(shù): {a} 和 ")
return a + b2. C++ 調(diào)用代碼
調(diào)用過程涉及 Python 對(duì)象的引用計(jì)數(shù)管理,這是最容易出錯(cuò)的地方。
#include <Python.h>
#include <iostream>
int main() {
Py_Initialize();
// 將當(dāng)前路徑加入 Python 的搜索路徑,否則找不到 script.py
PyRun_SimpleString("import sys; sys.path.append('.')");
// 加載模塊
PyObject* pModule = PyImport_ImportModule("script");
if (pModule) {
// 獲取函數(shù)對(duì)象
PyObject* pFunc = PyObject_GetAttrString(pModule, "add");
if (pFunc && PyCallable_Check(pFunc)) {
// 創(chuàng)建參數(shù)元組 (3, 5)
PyObject* pArgs = PyTuple_Pack(2, PyLong_FromLong(3), PyLong_FromLong(5));
// 調(diào)用函數(shù)
PyObject* pValue = PyObject_CallObject(pFunc, pArgs);
if (pValue) {
std::cout << "C++ 收到結(jié)果: " << PyLong_AsLong(pValue) << std::endl;
Py_DECREF(pValue);
}
Py_DECREF(pArgs);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
} else {
PyErr_Print(); // 打印 Python 錯(cuò)誤堆棧
}
Py_Finalize();
return 0;
}核心 API 詳解
| 函數(shù) | 功能 |
| Py_Initialize() | 啟動(dòng) Python 解釋器并加載基本模塊。 |
| PyRun_SimpleString() | 執(zhí)行單行 Python 代碼,簡(jiǎn)單快捷,但無法獲取返回值。 |
| PyImport_ImportModule() | 動(dòng)態(tài)加載一個(gè) .py 模塊。 |
| PyObject_GetAttrString() | 從模塊中獲取屬性(如函數(shù)、類)。 |
| PyTuple_Pack() | 將 C++ 數(shù)據(jù)打包成 Python 的元組,用于函數(shù)傳參。 |
| Py_DECREF() | 減少引用計(jì)數(shù)。極其重要,否則會(huì)導(dǎo)致嚴(yán)重的內(nèi)存泄漏。 |
避坑指南(經(jīng)驗(yàn)總結(jié))
- 路徑問題:Python 解釋器默認(rèn)不搜索 C++ 可執(zhí)行文件目錄。務(wù)必使用
sys.path.append('.')或設(shè)置PYTHONPATH環(huán)境變量。 - Debug/Release 陷阱:在 Windows 上,如果你編譯 C++ 為 Debug 模式,它會(huì)嘗試尋找
python3x_d.lib。如果你的 Python 環(huán)境沒有安裝調(diào)試庫,請(qǐng)確保 C++ 使用 Release 模式,或者手動(dòng)修改宏定義。 - 引用計(jì)數(shù):遵循“誰創(chuàng)建,誰負(fù)責(zé)”的原則。如果你通過
PyImport或PyObject_Get獲得了對(duì)象,不用時(shí)必須Py_DECREF。 - 多線程 (GIL):如果你的 C++ 程序是多線程的,且多個(gè)線程都要調(diào)用 Python,你需要處理 GIL (Global Interpreter Lock)。
總結(jié)
通過 Py_Initialize 嵌入 Python,為 C++ 程序打開了一扇通往無限庫資源的大門。雖然 Python C API 的語法略顯繁瑣(尤其是內(nèi)存管理),但它帶來的靈活性是無與倫比的。
到此這篇關(guān)于C++通過 Py_Initialize實(shí)現(xiàn)對(duì)Python的嵌入調(diào)用的文章就介紹到這了,更多相關(guān)C++嵌入調(diào)用Python內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
用c語言實(shí)現(xiàn)冒泡排序,選擇排序,快速排序
本篇文章是對(duì)使用c語言實(shí)現(xiàn)冒泡排序,選擇排序,快速排序的代碼進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
利用C語言實(shí)現(xiàn)將格式化數(shù)據(jù)和字符串相互轉(zhuǎn)換
這篇文章主要為大家詳細(xì)介紹了2個(gè)函數(shù),分別是sprintf和sscanf,可以用來實(shí)現(xiàn)將格式化數(shù)據(jù)和字符串相互轉(zhuǎn)換,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-03-03
C++強(qiáng)制轉(zhuǎn)換與智能指針示例詳解
這篇文章主要介紹了C++強(qiáng)制轉(zhuǎn)換與智能指針示例,智能指針(Smart Pointer)是一種抽象的數(shù)據(jù)類型。在程序設(shè)計(jì)中,它通常是經(jīng)由類模板來實(shí)現(xiàn),借由模板來達(dá)成泛型,借由類別的析構(gòu)函數(shù)來達(dá)成自動(dòng)釋放指針?biāo)赶虻拇鎯?chǔ)器或?qū)ο?/div> 2022-11-11
C/C++函數(shù)參數(shù)聲明解析int?fun()?與?int?fun(void)?的區(qū)別講解
C++中int fun()和int fun(void)的區(qū)別在于函數(shù)參數(shù)的聲明方式,前者默認(rèn)允許任意參數(shù),而后者表示沒有參數(shù),通過清晰的實(shí)例源代碼,詳細(xì)解釋了它們?cè)诤瘮?shù)聲明和調(diào)用中的不同之處,這篇文章介紹了C/C++函數(shù)參數(shù)聲明int?fun()與int?fun(void)的差異,需要的朋友可以參考下2024-01-01
C++11可變參數(shù)模板的具體實(shí)現(xiàn)
C++11引入的可變參數(shù)模板是一項(xiàng)非常強(qiáng)大的特性,它極大地提升了模板的擴(kuò)展性,可變參數(shù)模板允許我們定義可以接受任意數(shù)量和類型參數(shù)的模板,這在處理不定數(shù)量參數(shù)的場(chǎng)景中非常有用,感興趣的可以了解一下2025-06-06
Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式)
這篇文章主要介紹了Qt 鼠標(biāo)/觸屏繪制平滑曲線(支持矢量/非矢量方式),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04
FFmpeg實(shí)現(xiàn)音頻漸響效果參數(shù)值詳解
這篇文章主要為大家介紹了FFmpeg實(shí)現(xiàn)音頻漸響效果參數(shù)值詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-10-10最新評(píng)論

