[AI智能体与提效-152] - Python 调用 C 代码的四种主要方式或者如何编写被Phthon直接调用的C代码,从简单到难度最大,通俗易懂
表格排名方式难度核心特点推荐用途1ctypes⭐免编译,直接调.so/.dll调用现成的第三方 C 库2pybind11⭐⭐自动化,C++ 风格,类型安全开发新的 C/C++ 库给 Python 用3Cython⭐⭐⭐混合体,Python 语法 + C 速度加速现有的 Python 代码4C API⭐⭐⭐⭐⭐纯手工,极度繁琐,易崩溃开发 Python 底层核心库一句话指南想用别人的库?选ctype
这是一个非常实用的问题。为了让你更容易上手,我们将顺序调整为从“最简单/最常用”到“最难/最底层”。
这就好比你想让一位外国工匠(C 代码)帮你干活,你有四种合作方式,从“直接打电话叫外卖”到“亲自去工地搬砖”难度依次递增。
第一级:ctypes / cffi —— “直接调用现成库”
【难度】:⭐ (最简单)
【核心概念】: 你不需要重新编译任何东西,也不需要写特殊的连接代码。只要 C 代码已经被编译成了动态库文件(Windows 下的 .dll,Linux/Mac 下的 .so),Python 就可以直接加载并调用它。
- 通俗比喻:
工匠已经盖好了一间成品小屋(动态库)。你(Python)只需要站在门口,拿着说明书(函数定义),对着窗口喊话:“喂,把灯打开!”工匠听到后执行操作,把结果递给你。你完全不用进屋,也不用管屋里怎么布线。 - 适用场景:调用操作系统自带的库(如
libc),或者第三方提供的已编译好的 C/C++ SDK。 - 如何编写:
- C 端:写正常的 C 代码,编译成共享库。c
编译命令 (Linux/Mac):// hello.c #include <stdio.h> void say_hello(const char* name) { printf("Hello from C: %s\n", name); }gcc -shared -fPIC -o libhello.so hello.c - Python 端:使用
ctypes加载并调用。pythonimport ctypes # 1. 加载库文件 lib = ctypes.CDLL("./libhello.so") # 2. 【重要】告诉 Python 参数的类型 (否则可能崩溃) lib.say_hello.argtypes = [ctypes.c_char_p] # 3. 调用 (注意传入 bytes 类型) lib.say_hello(b"World")
- C 端:写正常的 C 代码,编译成共享库。c
- 优点:无需安装额外包(
ctypes是 Python 内置的),无需复杂的编译配置。 - 缺点:类型检查在运行时进行,如果参数类型写错,程序会直接崩溃;处理复杂数据结构(如结构体嵌套)比较麻烦。
第二级:pybind11 —— “现代 C++ 的自动绑定”,把C代码包装成Python的通用模块,由通用模块机制负责转换Python调用转换成C调用。
【难度】:⭐⭐ (简单偏中)
【核心概念】: 这是一个基于 C++11 的头文件库。虽然它主要面向 C++,但完全可以用来封装 C 函数。你只需要写很少的“注册代码”,它就能自动生成所有复杂的连接逻辑。
- 通俗比喻:
你给工匠发了一份简单的菜单(几行 C++ 代码),上面写着:“我有这些功能”。pybind11 就像是一个智能机器人,它读完菜单,自动帮你在 Python 和 C 之间搭建好完美的沟通桥梁,连语言翻译、异常处理都帮你做好了。 - 适用场景:你正在开发一个新的 C/C++ 库,并希望它能方便地被 Python 调用。这是目前工业界的主流选择。
- 如何编写:
- C/C++ 端:写一个绑定文件(比如
binding.cpp)。#include <pybind11/pybind11.h> namespace py = pybind11; // 假设这是你的普通 C 函数 void c_say_hello(const char* name) { printf("Hello via pybind11: %s\n", name); } // 定义模块,只需几行 // hello_mod: Pyhton看到的模块名 // say_hello: Python看到的函数名 // c_say_hello: C代码中的函数名 PYBIND11_MODULE(hello_mod, m) { m.def("say_hello", &c_say_hello, "Say hello function"); } - 编译:编写
setup.py或使用CMakeLists.txt进行编译(需要安装pybind11库)。 - Python 端:直接导入使用。python
编辑
import hello_mod hello_mod.say_hello("World") # 自动处理字符串转换,无需 bytes
- C/C++ 端:写一个绑定文件(比如
- 优点:代码极少,类型安全,自动处理异常,支持复杂 C++ 特性(类、模板等)。
- 缺点:需要配置 C++ 编译环境(如 CMake),对纯 C 项目需要包一层 C++。
第三级:Cython —— “带魔法注释的 Python”, C语言风格的Python语法,对Python语法的扩展,自动把这种类型的Python代码编译成C代码,可以在Python直接调用。
【难度】:⭐⭐⭐ (中等)
【核心概念】: Cython 是一种独立的语言,它是 Python 的超集。你写的代码看起来像 Python,但加上一些特殊的类型声明(cdef)后,Cython 编译器会自动把它翻译成高效的 C 代码,并编译成 Python 扩展模块。
- 通俗比喻:
你穿着便装(Python 语法)去工地,但在关键部位贴上魔法标签(类型声明)。Cython 编译器就像一个变身器,它读取你的代码,瞬间把你变成全副武装的 C 工程师,并自动生成所有必要的连接代码。你既享受了 Python 的简洁,又获得了 C 的速度。把现有的Python代码转换成C代码。 - 适用场景:加速现有的 Python 代码(特别是密集的循环和数学计算),或者用类似 Python 的语法编写 C 扩展。
- 如何编写:
- 编写 .pyx 文件:python
编辑
# hello.pyx def say_hello(str name): # 普通 Python 函数 print(f"Hello via Cython: {name}") # 魔法时刻:声明 C 变量 cdef int i cdef long total = 0 for i in range(10000000): total += i # 这行会被编译成纯 C 循环,飞快! return total - 编译:编写
setup.py,运行python setup.py build_ext --inplace。Cython 会先转成 C,再编译成.so/.pyd。 - Python 端:python
编辑
import hello print(hello.say_hello("World"))
- 编写 .pyx 文件:python
- 优点:语法最接近 Python,学习成本低,性能提升巨大。
- 缺点:需要学习少量的特殊语法(
cdef,cpdef),调试错误信息有时不如纯 Python 直观。
第四级:Python C API —— “手写原生扩展”
【难度】:⭐⭐⭐⭐⭐ (最难,地狱级)
【核心概念】: 这是 Python 解释器官方提供的最底层接口。你必须完全用 C 语言编写代码,严格遵守 Python 的内存管理规则(引用计数),手动处理所有类型转换。
- 通俗比喻:
你要亲自进入 Python 皇宫的核心机房。你必须穿上严格的制服(PyObject结构),每拿一个工具都要登记(增加引用计数),用完必须亲手归还(减少引用计数)。如果你忘了归还任何一个螺丝刀,整个皇宫(解释器)就会因为资源耗尽而崩塌(Segmentation Fault)。没有任何自动化工具帮你,一切全靠手写。 - 适用场景:开发 Python 标准库级别的底层模块(如
numpy,tensorflow的底层),或者需要对 Python 内部机制进行极致控制时。 - 如何编写:
- 编写 C 代码:必须包含
Python.h,遵循严格的函数签名。c编辑
#include <Python.h> static PyObject* say_hello(PyObject *self, PyObject *args) { const char *name; // 手动解析参数,失败返回 NULL if (!PyArg_ParseTuple(args, "s", &name)) return NULL; printf("Hello via C API: %s\n", name); // 手动返回 None 对象 (引用计数已处理好) Py_RETURN_NONE; } // 手动定义方法表 static PyMethodDef Methods[] = { {"say_hello", say_hello, METH_VARARGS, "Say hello"}, {NULL, NULL, 0, NULL} }; // 手动定义模块结构 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "hello_api", NULL, -1, Methods }; // 手动定义初始化函数 PyMODINIT_FUNC PyInit_hello_api(void) { return PyModule_Create(&moduledef); } - 编译:编写复杂的
setup.py进行编译。 - Python 端:导入使用。
- 编写 C 代码:必须包含
- 优点:性能最高,无中间层开销,完全控制。
- 缺点:代码量巨大,极易出错(内存泄漏、段错误),维护成本极高。除非必要,否则不推荐初学者使用。
总结与选型建议
表格
| 排名 | 方式 | 难度 | 核心特点 | 推荐用途 |
|---|---|---|---|---|
| 1 | ctypes | ⭐ | 免编译,直接调 .so/.dll |
调用现成的第三方 C 库 |
| 2 | pybind11 | ⭐⭐ | 自动化,C++ 风格,类型安全 | 开发新的 C/C++ 库给 Python 用 |
| 3 | Cython | ⭐⭐⭐ | 混合体,Python 语法 + C 速度 | 加速现有的 Python 代码 |
| 4 | C API | ⭐⭐⭐⭐⭐ | 纯手工,极度繁琐,易崩溃 | 开发 Python 底层核心库 |
一句话指南:
- 想用别人的库?选 ctypes。
- 想写新库给别人用?选 pybind11。
- 想加速自己的 Python 代码?选 Cython。
- 想挑战人类极限或造轮子?选 C API。
更多推荐



所有评论(0)