在 C 语言中调用 Python 脚本示例

xwbar的头像
2025-11-28 14:35:50
/
活动首发

在 C 语言中调用 Python 脚本示例

在 C 语言中调用 Python 脚本的方式有很多,在这里使用 Python 的 C API 进行调用 Python 脚本,包括初始化解释器、执行脚本文件(导入模块和类、创建对象、调用对象方法)以及处理错误的完整流程。

参考 Python 的 C API 文档:

Python/C API 参考手册

示例代码:python_c_api_demo

环境准备

示例使用的是 Python3.9 ,需要安装 python 3.9 以及 python3-dev

安装 gcc

执行环境必须有 Python 环境

简单调用示例

单线程导入模块以及类,创建对象,调用对象方法。

Python 脚本

example.py

import random

import time

class HelloWorld:

def __init__(self, name):

self.name = name

def say_hi(self):

print(f'Hi {self.name}')

def add(self, a, b):

return a + b

def random_number(self):

time.sleep(0.05)

return random.randint(0, 100)

C 语言代码

直接在 example.c 中执行 Python 脚本。

#include

int main()

{

// 初始化 Python 解释器

Py_Initialize();

// 添加当前目录到 sys.path(确保能导入 example.py)

PyObject *pSys = PyImport_ImportModule("sys");

if (!pSys)

{

PyErr_Print();

fprintf(stderr, "Failed to import sys module\n");

return 1;

}

PyObject *pPath = PyObject_GetAttrString(pSys, "path");

if (!pPath)

{

PyErr_Print();

fprintf(stderr, "Failed to get sys.path\n");

Py_DECREF(pSys);

return 1;

}

int status = PyList_Append(pPath, PyUnicode_FromString("."));

if (status == -1)

{

PyErr_Print();

fprintf(stderr, "Failed to append path\n");

Py_DECREF(pPath);

Py_DECREF(pSys);

return 1;

}

Py_DECREF(pPath);

Py_DECREF(pSys);

// 导入 example 模块

PyObject *pModule = PyImport_ImportModule("example");

if (!pModule)

{

PyErr_Print();

fprintf(stderr, "Failed to import example module\n");

Py_Finalize();

return 1;

}

// 导入 HelloWorld 类

PyObject *pClass = PyObject_GetAttrString(pModule, "HelloWorld");

if (!pClass)

{

PyErr_Print();

fprintf(stderr, "Failed to import HelloWorld class\n");

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

// 创建对象

char name[256] = "XiaoMing";

PyObject *pArgs = PyTuple_New(1);

PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(name));

PyObject *pInstance = PyObject_CallObject(pClass, pArgs);

Py_DECREF(pArgs);

if (pInstance == NULL)

{

PyErr_Print();

fprintf(stderr, "Failed to create instance of HelloWorld\n");

Py_XDECREF(pClass);

Py_XDECREF(pModule);

return 1;

}

// 获取 say_hi 方法

PyObject *pFuncSayHi = PyObject_GetAttrString(pInstance, "say_hi");

if (!pFuncSayHi || !PyCallable_Check(pFuncSayHi))

{

PyErr_Print();

fprintf(stderr, "Failed to get say_hi function\n");

Py_DECREF(pInstance);

Py_DECREF(pClass);

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

// 调用 say_hi 方法

PyObject_CallObject(pFuncSayHi, NULL);

// 获取 add 函数

PyObject *pFuncAdd = PyObject_GetAttrString(pInstance, "add");

if (!pFuncAdd || !PyCallable_Check(pFuncAdd))

{

PyErr_Print();

fprintf(stderr, "Failed to get add function\n");

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

Py_DECREF(pClass);

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

// 构造参数并调用 add 函数

PyObject *pArgsAdd = PyTuple_Pack(2, PyLong_FromLong(3), PyLong_FromLong(4));

if (!pArgsAdd)

{

PyErr_Print();

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

Py_DECREF(pClass);

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

PyObject *pResultAdd = PyObject_CallObject(pFuncAdd, pArgsAdd);

if (!pResultAdd)

{

PyErr_Print();

fprintf(stderr, "Failed to call add function\n");

Py_DECREF(pArgsAdd);

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

Py_DECREF(pClass);

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

// 处理返回值

long addResult = PyLong_AsLong(pResultAdd);

printf("Add Result: %ld\n", addResult);

// 获取 random_number 方法

PyObject *pFuncRandomNumber = PyObject_GetAttrString(pInstance, "random_number");

if (!pFuncRandomNumber || !PyCallable_Check(pFuncRandomNumber))

{

PyErr_Print();

fprintf(stderr, "Failed to get random_number function\n");

Py_DECREF(pResultAdd);

Py_DECREF(pArgsAdd);

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

Py_DECREF(pClass);

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

// 调用 random_number 方法

PyObject *pRandomNumber = PyObject_CallObject(pFuncRandomNumber, NULL);

long randomNumber = PyLong_AsLong(pRandomNumber);

printf("Random Number: %ld\n", randomNumber);

// 释放资源

Py_DECREF(pRandomNumber);

Py_DECREF(pFuncRandomNumber);

Py_DECREF(pResultAdd);

Py_DECREF(pArgsAdd);

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

Py_DECREF(pClass);

Py_DECREF(pModule);

// 结束 Python 解释器

Py_Finalize();

return 0;

}

编译命令:gcc example.c -I/usr/include/python3.9 -lpython3.9 -o example

多线程调用示例

当在 C 程序中创建多线程调用 Python API 时,必须注意 GIL 的获取和释放,使用 PyGILState_Ensure() 和 PyGILState_Release() 来获取和释放 GIL。

在主线程使用Py_Initialize初始化 Python 解释器后,主线程会自动持有 GIL,必须显式释放 GIL,否则子线程中会一直阻塞在获取 GIL

example_threading.c

在主线程中初始化 Python 解释器,并导入模块和类,创建多个线程,每个线程都创建对象,并调用对象方法。

#include

#define NUM_THREADS 5

#define NUM_ITERATIONS 50

// 线程参数结构

typedef struct

{

int thread_id;

const char *name;

PyObject *pClass;

} ThreadArgs;

// 生成随机字符串的函数

void generate_random_string(char *buffer, int length, const char *charset)

{

int charset_len = strlen(charset);

for (int i = 0; i < length; ++i)

{

int index = rand() % charset_len; // 从字符集中随机选一个字符

buffer[i] = charset[index];

}

}

// 线程函数

void *thread_func(void *args)

{

ThreadArgs *targs = (ThreadArgs *)args;

int tid = targs->thread_id;

printf("Thread %d started\n", tid);

PyGILState_STATE gstate;

gstate = PyGILState_Ensure();

PyObject *pArgs = PyTuple_New(1);

PyTuple_SetItem(pArgs, 0, PyUnicode_FromString(targs->name));

PyGILState_Release(gstate);

gstate = PyGILState_Ensure();

PyObject *pInstance = PyObject_CallObject(targs->pClass, pArgs);

Py_DECREF(pArgs);

if (pInstance == NULL)

{

PyErr_Print();

fprintf(stderr, "Failed to create instance of HelloWorld\n");

PyGILState_Release(gstate);

return NULL;

}

PyGILState_Release(gstate);

// 获取 say_hi 方法

gstate = PyGILState_Ensure();

PyObject *pFuncSayHi = PyObject_GetAttrString(pInstance, "say_hi");

if (!pFuncSayHi || !PyCallable_Check(pFuncSayHi))

{

PyErr_Print();

fprintf(stderr, "Failed to get say_hi function\n");

Py_DECREF(pInstance);

PyGILState_Release(gstate);

Py_Finalize();

return NULL;

}

// 调用 say_hi 方法

PyObject_CallObject(pFuncSayHi, NULL);

PyGILState_Release(gstate);

// 获取 add 函数

gstate = PyGILState_Ensure();

PyObject *pFuncAdd = PyObject_GetAttrString(pInstance, "add");

if (!pFuncAdd || !PyCallable_Check(pFuncAdd))

{

PyErr_Print();

fprintf(stderr, "Failed to get add function\n");

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

PyGILState_Release(gstate);

Py_Finalize();

return NULL;

}

// 构造参数并调用 add 函数

PyObject *pArgsAdd = PyTuple_Pack(2, PyLong_FromLong(3), PyLong_FromLong(4));

if (!pArgsAdd)

{

PyErr_Print();

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

PyGILState_Release(gstate);

Py_Finalize();

return NULL;

}

PyObject *pResultAdd = PyObject_CallObject(pFuncAdd, pArgsAdd);

if (!pResultAdd)

{

PyErr_Print();

fprintf(stderr, "Failed to call add function\n");

Py_DECREF(pArgsAdd);

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

PyGILState_Release(gstate);

Py_Finalize();

return NULL;

}

// 处理返回值

long addResult = PyLong_AsLong(pResultAdd);

PyGILState_Release(gstate);

printf("Add Result: %ld\n", addResult);

// 获取 random_number 方法

gstate = PyGILState_Ensure();

PyObject *pFuncRandomNumber = PyObject_GetAttrString(pInstance, "random_number");

if (!pFuncRandomNumber || !PyCallable_Check(pFuncRandomNumber))

{

PyErr_Print();

fprintf(stderr, "Failed to get random_number function\n");

Py_DECREF(pResultAdd);

Py_DECREF(pArgsAdd);

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

PyGILState_Release(gstate);

Py_Finalize();

return NULL;

}

PyGILState_Release(gstate);

srand(time(NULL) + tid);

// 循环多次调用 random_number 方法

for (int i = 0; i < NUM_ITERATIONS; i++)

{

gstate = PyGILState_Ensure();

PyObject *pRandomNumber = PyObject_CallObject(pFuncRandomNumber, NULL);

long randomNumber = PyLong_AsLong(pRandomNumber);

printf("Thread %d, Iteration %d, Random Number: %ld\n", tid, i, randomNumber);

Py_DECREF(pRandomNumber);

PyGILState_Release(gstate);

usleep(10000);

}

// 释放资源

gstate = PyGILState_Ensure();

Py_DECREF(pFuncRandomNumber);

Py_DECREF(pResultAdd);

Py_DECREF(pArgsAdd);

Py_DECREF(pFuncAdd);

Py_DECREF(pFuncSayHi);

Py_DECREF(pInstance);

PyGILState_Release(gstate);

printf("Thread %d end\n", tid);

return NULL;

}

int main()

{

// 主线程初始化一次 Python 解释器

Py_Initialize();

// 添加当前目录到 sys.path(确保能导入 example.py)

PyObject *pSys = PyImport_ImportModule("sys");

if (!pSys)

{

PyErr_Print();

fprintf(stderr, "Failed to import sys module\n");

return 1;

}

PyObject *pPath = PyObject_GetAttrString(pSys, "path");

if (!pPath)

{

PyErr_Print();

fprintf(stderr, "Failed to get sys.path\n");

Py_DECREF(pSys);

return 1;

}

int status = PyList_Append(pPath, PyUnicode_FromString("."));

if (status == -1)

{

PyErr_Print();

fprintf(stderr, "Failed to append path\n");

Py_DECREF(pPath);

Py_DECREF(pSys);

return 1;

}

Py_DECREF(pPath);

Py_DECREF(pSys);

// 导入 example 模块

PyObject *pModule = PyImport_ImportModule("example");

if (!pModule)

{

PyErr_Print();

fprintf(stderr, "Failed to import example module\n");

Py_Finalize();

return 1;

}

// 导入 HelloWorld 类

PyObject *pClass = PyObject_GetAttrString(pModule, "HelloWorld");

if (!pClass)

{

PyErr_Print();

fprintf(stderr, "Failed to import HelloWorld class\n");

Py_DECREF(pModule);

Py_Finalize();

return 1;

}

PyEval_SaveThread(); // 释放 GIL

srand(time(NULL)); // 初始化随机种子

const char *charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

// 创建线程

pthread_t threads[NUM_THREADS];

ThreadArgs thread_args[NUM_THREADS];

for (int i = 0; i < NUM_THREADS; ++i)

{

printf("Create thread %d\n", i);

char buffer[5]; // 长度为 5 个结束符

generate_random_string(buffer, 5, charset);

thread_args[i].thread_id = i;

thread_args[i].name = buffer;

thread_args[i].pClass = pClass;

int rc = pthread_create(&threads[i], NULL, thread_func, &thread_args[i]);

if (rc)

{

fprintf(stderr, "Error creating thread %d\n", i);

return EXIT_FAILURE;

}

// usleep(100000);

}

printf("create threads success\n");

for (int i = 0; i < NUM_THREADS; ++i)

{

pthread_join(threads[i], NULL);

}

PyGILState_STATE gstate = PyGILState_Ensure();

Py_DECREF(pClass);

Py_DECREF(pModule);

// 结束 Python 解释器

Py_Finalize();

return 0;

}

编译命令:gcc example_threading.c -I/usr/include/python3.9 -lpython3.9 -lpthread -o example_threading

跨平台编译

在 x64 上编译到 arm64 平台的可执行文件,需要将目标设备上的 python 相关头文件和库文件复制到编译机上,并使用 aarch64-linux-gnu-gcc 编译。

编译命令:aarch64-linux-gnu-gcc example_threading.c -o example_threading_arm64 -I./arm64-python3.12/include/python3.12 -L./arm64-python3.12/lib -lpython3.12 -lpthread -lm -lutil -ldl -Wl,-rpath,.

问题

在 Python 脚本中使用 Numpy 时,出现报错:numpy:DLL load failed while importing _multiarray_umath:,如果 Python 库中使用了 C 扩展,应该都会有这个问题,参考Numpy import fails on multiarray extension library when called from embedded Python within a C++ application的解决方案:在初始化 python 解释器前,动态加载 python 的 so 库

#include

dlopen("libpython3.9.so", RTLD_LAZY | RTLD_GLOBAL)

微信绑定手机号的步骤详解及注意事项
中国移动短号怎么取消?最新取消方法及注意事项!