这是一个非常实用的问题。为了让你更容易上手,我们将顺序调整为从“最简单/最常用”到“最难/最底层”

这就好比你想让一位外国工匠(C 代码)帮你干活,你有四种合作方式,从“直接打电话叫外卖”到“亲自去工地搬砖”难度依次递增。


第一级:ctypes / cffi —— “直接调用现成库”

【难度】:⭐ (最简单)
【核心概念】: 你不需要重新编译任何东西,也不需要写特殊的连接代码。只要 C 代码已经被编译成了动态库文件(Windows 下的 .dll,Linux/Mac 下的 .so),Python 就可以直接加载并调用它。

  • 通俗比喻
    工匠已经盖好了一间成品小屋(动态库)。你(Python)只需要站在门口,拿着说明书(函数定义),对着窗口喊话:“喂,把灯打开!”工匠听到后执行操作,把结果递给你。你完全不用进屋,也不用管屋里怎么布线。
  • 适用场景调用操作系统自带的库(如 libc),或者第三方提供的已编译好的 C/C++ SDK。
  • 如何编写
    1. C 端:写正常的 C 代码,编译成共享库。c
      // hello.c
      #include <stdio.h>
      void say_hello(const char* name) {
          printf("Hello from C: %s\n", name);
      }
      编译命令 (Linux/Mac): gcc -shared -fPIC -o libhello.so hello.c
    2. Python 端:使用 ctypes 加载并调用。python
      import ctypes
      
      # 1. 加载库文件
      lib = ctypes.CDLL("./libhello.so")
      
      # 2. 【重要】告诉 Python 参数的类型 (否则可能崩溃)
      lib.say_hello.argtypes = [ctypes.c_char_p]
      
      # 3. 调用 (注意传入 bytes 类型)
      lib.say_hello(b"World")
  • 优点:无需安装额外包(ctypes 是 Python 内置的),无需复杂的编译配置。
  • 缺点:类型检查在运行时进行,如果参数类型写错,程序会直接崩溃;处理复杂数据结构(如结构体嵌套)比较麻烦。

第二级:pybind11 —— “现代 C++ 的自动绑定”,把C代码包装成Python的通用模块,由通用模块机制负责转换Python调用转换成C调用。

【难度】:⭐⭐ (简单偏中)
【核心概念】: 这是一个基于 C++11头文件库。虽然它主要面向 C++,但完全可以用来封装 C 函数。你只需要写很少的“注册代码”,它就能自动生成所有复杂的连接逻辑。

  • 通俗比喻
    你给工匠发了一份简单的菜单(几行 C++ 代码),上面写着:“我有这些功能”。pybind11 就像是一个智能机器人,它读完菜单,自动帮你在 Python 和 C 之间搭建好完美的沟通桥梁,连语言翻译、异常处理都帮你做好了。
  • 适用场景:你正在开发一个新的 C/C++ 库,并希望它能方便地被 Python 调用。这是目前工业界的主流选择。
  • 如何编写
    1. 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");
      }
    2. 编译:编写 setup.py 或使用 CMakeLists.txt 进行编译(需要安装 pybind11 库)。
    3. Python 端:直接导入使用。python

      编辑

      import hello_mod
      hello_mod.say_hello("World") # 自动处理字符串转换,无需 bytes
  • 优点代码极少,类型安全,自动处理异常,支持复杂 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 扩展。
  • 如何编写
    1. 编写 .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
    2. 编译:编写 setup.py,运行 python setup.py build_ext --inplace。Cython 会先转成 C,再编译成 .so/.pyd
    3. Python 端:python

      编辑

      import hello
      print(hello.say_hello("World"))
  • 优点:语法最接近 Python,学习成本低,性能提升巨大。
  • 缺点:需要学习少量的特殊语法(cdefcpdef),调试错误信息有时不如纯 Python 直观。

第四级:Python C API —— “手写原生扩展”

【难度】:⭐⭐⭐⭐⭐ (最难,地狱级)
【核心概念】: 这是 Python 解释器官方提供的最底层接口。你必须完全用 C 语言编写代码,严格遵守 Python 的内存管理规则(引用计数),手动处理所有类型转换。

  • 通俗比喻
    你要亲自进入 Python 皇宫的核心机房。你必须穿上严格的制服(PyObject 结构),每拿一个工具都要登记(增加引用计数),用完必须亲手归还(减少引用计数)。如果你忘了归还任何一个螺丝刀,整个皇宫(解释器)就会因为资源耗尽而崩塌(Segmentation Fault)。没有任何自动化工具帮你,一切全靠手写。
  • 适用场景:开发 Python 标准库级别的底层模块(如 numpytensorflow 的底层),或者需要对 Python 内部机制进行极致控制时。
  • 如何编写
    1. 编写 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);
      }
    2. 编译:编写复杂的 setup.py 进行编译。
    3. Python 端:导入使用。
  • 优点:性能最高,无中间层开销,完全控制。
  • 缺点:代码量巨大,极易出错(内存泄漏、段错误),维护成本极高。除非必要,否则不推荐初学者使用。

总结与选型建议

表格

排名 方式 难度 核心特点 推荐用途
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
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐