1. ctypes(标准库)
import ctypes
import os
# 加载动态库
lib = ctypes.CDLL('./mylib.so') # Linux
# lib = ctypes.CDLL('mylib.dll') # Windows
# 调用C函数
lib.my_function.argtypes = [ctypes.c_int, ctypes.c_float]
lib.my_function.restype = ctypes.c_double
result = lib.my_function(10, 3.14)
特点:
- ✅ Python标准库,无需额外依赖
- ✅ 支持动态加载,无需重新编译
- ⚠️ 需要手动处理类型转换
- ⚠️ 错误处理较为原始
2. CFFI(C Foreign Function Interface)
from cffi import FFI
ffi = FFI()
ffi.cdef("""
double my_function(int a, float b);
""")
lib = ffi.dlopen('./mylib.so')
result = lib.my_function(10, 3.14)
特点:
- ✅ 更符合Python风格
- ✅ 支持in-line C代码
- ✅ 类型检查更严格
- ⚠️ 需要安装额外包:
pip install cffi
3. Python C API(最底层)
// C扩展模块
#include <Python.h>
static PyObject* py_my_function(PyObject* self, PyObject* args) {
int a;
float b;
if (!PyArg_ParseTuple(args, "if", &a, &b))
return NULL;
double result = my_function(a, b);
return PyFloat_FromDouble(result);
}
特点:
- ✅ 性能最优
- ✅ 完全控制内存和错误处理
- ❌ 代码最复杂,易出错
- ❌ 需要处理Python版本兼容性
4. PyBind11(现代C++绑定)
#include <pybind11/pybind11.h>
#include "my_library.h"
PYBIND11_MODULE(example, m) {
m.def("my_function", &my_function,
"A function that adds two numbers",
py::arg("a"), py::arg("b"));
}
特点:
- ✅ 自动类型转换
- ✅ 支持现代C++特性
- ✅ 简洁的语法
- ⚠️ 需要C++11+编译器
- ⚠️
pip install pybind11
5. Cython
# example.pyx
cdef extern from "my_library.h":
double my_function(int a, float b)
def py_my_function(int a, float b):
return my_function(a, b)
特点:
- ✅ Python语法的超集
- ✅ 混合Python和C代码
- ✅ 优秀的性能平衡
- ⚠️ 需要学习Cython语法
- ⚠️ 需要编译步骤
综合对比表格
| 特性 |
ctypes |
CFFI |
Python C API |
PyBind11 |
Cython |
|---|
| 学习曲线 |
简单 |
中等 |
陡峭 |
中等 |
中等 |
| 性能 |
良好 |
良好 |
优秀 |
优秀 |
优秀 |
| 内存安全 |
低 |
高 |
取决于实现 |
高 |
高 |
| 开发速度 |
快 |
快 |
慢 |
中等 |
快 |
| 维护成本 |
低 |
低 |
高 |
中等 |
中等 |
| 跨平台 |
优秀 |
优秀 |
优秀 |
优秀 |
优秀 |
| 调试难度 |
简单 |
中等 |
困难 |
中等 |
中等 |
选择建议
快速原型 → ctypes或CFFI
性能关键 → PyBind11或Cython
复杂C++项目 → PyBind11
已有Python代码优化 → Cython
- 逐步优化现有Python代码
- 混合Python和C逻辑
底层控制 → Python C API
性能测试示例
import timeit
# 测试不同方式的调用开销
ctypes_time = timeit.timeit('lib.my_func(1, 2.0)',
setup='import ctypes; lib=...')
cffi_time = timeit.timeit('lib.my_func(1, 2.0)',
setup='from cffi import FFI; ffi=...')
# 通常:Python C API ≈ PyBind11 < Cython < CFFI < ctypes
最佳实践
从ctypes/CFFI开始,验证功能可行性
使用PyBind11进行生产部署(C++项目)
用Cython包装现有的C库(C项目)
始终添加类型检查和错误处理
提供纯Python回退实现以便调试
选择时考虑团队熟悉度、项目规模和性能需求,通常PyBind11和Cython在平衡开发效率和运行时性能方面表现最佳。