在 Python 中访问用 C 语言编写的模块,通常是通过 Python C API 实现的。Python 提供了丰富的 C API,允许你将 C 代码编译为 Python 模块,从而在 Python 中直接调用 C 函数。
以下是实现步骤的详细说明:
1. 编写 C 代码
首先,编写一个 C 文件,定义你想要在 Python 中调用的函数。
示例:mymodule.c
#include <Python.h>
// C 函数实现
static PyObject* mymodule_hello(PyObject* self, PyObject* args) {
const char* name;
if (!PyArg_ParseTuple(args, "s", &name)) {
return NULL;
}
printf("Hello, %s!\n", name);
Py_RETURN_NONE;
}
// 方法表,定义模块中的函数
static PyMethodDef MyModuleMethods[] = {
{"hello", mymodule_hello, METH_VARARGS, "Print a hello message"},
{NULL, NULL, 0, NULL} // 结束标志
};
// 模块定义
static struct PyModuleDef mymodule = {
PyModuleDef_HEAD_INIT,
"mymodule", // 模块名
NULL, // 模块文档
-1, // 模块状态大小
MyModuleMethods
};
// 模块初始化函数
PyMODINIT_FUNC PyInit_mymodule(void) {
return PyModule_Create(&mymodule);
}
2. 编译 C 代码为 Python 模块
将 C 代码编译为 Python 可加载的模块(.so 或 .pyd 文件)。
使用 setup.py 编译
创建一个 setup.py 文件:
from setuptools import setup, Extension
module = Extension(
'mymodule', # 模块名
sources=['mymodule.c'], # C 源文件
)
setup(
name='mymodule',
version='1.0',
description='A simple C extension module',
ext_modules=[module],
)
运行以下命令编译模块:
python setup.py build
安装模块:
python setup.py install
编译完成后,会生成一个 .so(Linux/macOS)或 .pyd(Windows)文件。
3. 在 Python 中调用 C 模块
编译完成后,可以在 Python 中直接导入并使用该模块。
示例:test.py
import mymodule
# 调用 C 模块中的函数
mymodule.hello("World")
Hello, World!
4. 详细步骤说明
1. C 代码结构
- Python.h:包含 Python C API 的头文件。
- PyObject:Python 对象的基类,所有 Python 对象都是 PyObject 或其子类。
- PyArg_ParseTuple:解析 Python 传递的参数。
- PyModuleDef:定义模块的结构。
- PyMODINIT_FUNC:模块初始化函数。
- 编译工具
- setuptools:Python 的构建工具,用于编译和安装扩展模块。
- Extension:定义扩展模块的名称和源文件。
3. 模块加载
- 编译后的模块会被安装到 Python 的 site-packages 目录中,可以直接导入。
5. 其他方式:使用 ctypes 或 cffi
如果你不想编写 Python C API 代码,可以使用 ctypes 或 cffi 直接调用 C 函数。
使用 ctypes
- 将 C 代码编译为共享库(.so 或 .dll)。
- 在 Python 中使用 ctypes 加载共享库并调用函数。
示例:
import ctypes
# 加载共享库
mylib = ctypes.CDLL('./mylib.so')
# 调用 C 函数
mylib.hello(b"World")
使用 cffi
安装 cffi:
pip install cffi
编写 Python 代码加载 C 函数:
from cffi import FFI
ffi = FFI()
ffi.cdef("void hello(const char* name);")
mylib = ffi.dlopen('./mylib.so')
# 调用 C 函数
mylib.hello(b"World")
6. 注意事项
- Python 版本兼容性:确保 C 代码与 Python 版本兼容。
- 内存管理:在 C 代码中正确处理 Python 对象的引用计数。
- 跨平台编译:在不同平台上(如 Windows、Linux、macOS)编译时,可能需要调整编译选项。
总结
- 使用 Python C API 可以将 C 代码编译为 Python 模块,适合高性能计算或与现有 C 代码集成。
- 使用 ctypes 或 cffi 可以更简单地调用 C 函数,但灵活性较低。
- 根据需求选择合适的方式,推荐使用 Python C API 以获得更好的性能和集成性。