首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言嵌入 Python 完整指南:從初始化到呼叫函數與傳遞參數

     編輯:關於C語言

架構概覽

C 語言透過 Python.h 提供的 C API 嵌入 Python 解譯器,實現雙向互動:

  1. 初始化 Python 執行環境
  2. 載入模組、取得字典、查找函數物件
  3. 建構參數元組、呼叫函數
  4. 解析回傳值、清理資源、關閉解譯器

Python 端模組:call.py

# call.py
def test():
    print('hello world')

def add(a, b):
    return a + b

C 端完整實現

#include <stdio.h>
#include <stdlib.h>
#include <Python.h>

int main(int argc, char *argv[]) {
    /* 1. 初始化 Python 解譯器 */
    Py_Initialize();
    if (!Py_IsInitialized()) {
        fprintf(stderr, "Python 初始化失敗\n");
        return -1;
    }

    /* 2. 將當前目錄加入模組搜尋路徑 */
    PyRun_SimpleString("import sys");
    PyRun_SimpleString("sys.path.append('./')");

    /* 3. 載入模組 */
    PyObject *pName = PyUnicode_FromString("call");  // Python 3 使用 PyUnicode
    PyObject *pModule = PyImport_Import(pName);
    Py_DECREF(pName);
    if (!pModule) {
        PyErr_Print();
        fprintf(stderr, "無法載入 call.py\n");
        Py_Finalize();
        return -1;
    }

    /* 4. 取得模組字典 */
    PyObject *pDict = PyModule_GetDict(pModule);
    if (!pDict) {
        Py_DECREF(pModule);
        Py_Finalize();
        return -1;
    }

    /* 5. 呼叫無參函數 test() */
    PyObject *pFunc = PyDict_GetItemString(pDict, "test");
    if (pFunc && PyCallable_Check(pFunc)) {
        PyObject_CallObject(pFunc, NULL);
    } else {
        fprintf(stderr, "找不到函數 test\n");
    }

    /* 6. 呼叫有參函數 add(3, 4) */
    pFunc = PyDict_GetItemString(pDict, "add");
    if (pFunc && PyCallable_Check(pFunc)) {
        PyObject *pArgs = PyTuple_New(2);
        PyTuple_SetItem(pArgs, 0, PyLong_FromLong(3));   // Python 3 用 PyLong
        PyTuple_SetItem(pArgs, 1, PyLong_FromLong(4));
        
        PyObject *pResult = PyObject_CallObject(pFunc, pArgs);
        Py_DECREF(pArgs);
        
        if (pResult) {
            long ret = PyLong_AsLong(pResult);           // Python 3 用 PyLong_AsLong
            printf("add result: %ld\n", ret);
            Py_DECREF(pResult);
        }
    } else {
        fprintf(stderr, "找不到函數 add\n");
    }

    /* 7. 清理與關閉 */
    Py_DECREF(pDict);
    Py_DECREF(pModule);
    Py_Finalize();
    return 0;
}

關鍵 API 對照表(Python 2 vs 3)

功能Python 2Python 3
字串建構PyString_FromStringPyUnicode_FromString
整數建構PyInt_FromLongPyLong_FromLong
整數解析PyInt_AsLongPyLong_AsLong
模組名稱PyString_FromStringPyUnicode_FromString

編譯與連結指令

# Linux/macOS (Python 3.8+)
gcc -o embed embed.c $(python3-config --cflags --ldflags)

# 或手動指定
gcc -o embed embed.c -I/usr/include/python3.8 -lpython3.8

常見錯誤與除錯技巧

  • ImportError:檢查 sys.path、模組檔名、__pycache__ 干擾
  • Segmentation fault:參數元組建構錯誤、參考計數不平衡(Py_DECREF 漏/重)
  • TypeError:Python 端函數簽名與 C 端傳遞參數不匹配
  • 善用 PyErr_Print() 印出 Python 例外堆疊

進階:Py_BuildValue 格式字串速查

"i"  - int
"l"  - long
"d"  - double
"s"  - char* (UTF-8)
"O"  - PyObject* (傳遞既有物件)
"(ii)" - 兩個 int 組成的 tuple
"[ii]" - 兩個 int 組成的 list
"{s:i, s:i}" - dict

使用 Py_BuildValue 簡化參數建構

/* 替代 PyTuple_New + PyTuple_SetItem 系列 */
PyObject *pArgs = Py_BuildValue("(ll)", 3, 4);  // 直接建構 (3, 4) tuple
PyObject *pResult = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved