Python使用ctypes调用C/C++动态链接库详解

Ryan
Ryan
发布时间:2026-10-13 | 3人浏览过
原创

本文详解Python如何通过官方ctypes库调用C/C++编译的动态链接库(DLL/so)。内容涵盖使用gcc编译扩展模块、Windows与Linux下的加载差异、绝对路径注意事项,以及通过反射机制安全调用函数以规避异常。该方式可有效突破Python GIL限制,利用多核CPU提升性能。

Python调用C/C++动态链接库的背景与优势

楔子

Python的执行效率相对有限,且受全局解释器锁(GIL)制约,难以充分利用多核CPU资源。虽然多进程是常见解决方案,但其开销较大且进程间通信复杂。因此,对于耗时操作,通常采用C或C++编写并编译为动态链接库(Windows下为dll,Linux下为so),再由Python调用。此外,通过扩展模块方式还能有效绕过GIL限制,实现真正的多核并行处理。

使用ctypes调用扩展模块的方法

Python调用扩展模块

Python官方提供的ctypes库是调用扩展模块的简便方式,兼容所有Python版本。借助ctypes,开发者可以轻松地加载并调用外部动态链接库。

动态模块编译与Python调用实战

演示


#include <stdio.h>

void test()
{
  printf("hello world\n");
}

首先定义一个简单的C函数,随后将其编译为扩展模块。无论Windows还是Linux,编译命令基本一致。本文以Windows环境为例,需安装MinGW或Visual Studio Code(此处选用MinGW,因其体积较小)。

gcc -o dll文件或者so文件 -shared c或者c++源文件

假设C源文件名为1.c,目标输出文件为mmp.dll,编译命令如下:gcc -o mmp.dll -shared 1.c

接下来,在Python中调用该模块。


import ctypes

# 使用ctypes很简单,直接import进来,然后使用ctypes.CDLL这个类来加载动态模块
# 如果在Windows上还可以使用ctypes.WinDLL。
# 因为看ctypes源码的话,会发现WinDLL也是一个类并且继承自CDLL
# 所以在linux上使用ctypes.CDLL,
# 而在Windows上既可以使用WinDLL、也可以使用CDLL加载动态模块
lib = ctypes.CDLL("./mmp.dll") # 加载之后就得到了扩展模块
# 我们可以直接通过.的方式去调用里面的函数了,会发现成功打印
lib.test() # hello world

# 但是为了确定是否存在这个函数,我们一般会使用反射去获取
# 因为如果函数不存在通过.的方式调用会抛异常的
func = getattr(lib, "test", None)
if func:
  print(func) # <_FuncPtr object at 0x0000029F75F315F0>
  func() # hello world


# 不存在test_xx这个函数,所以得到的结果为None
func1 = getattr(lib, "test_xx", None)
print(func1) # None

使用ctypes调用扩展模块非常便捷。

具体步骤如下: 1. 使用ctypes.CDLL("dll或so路径")加载模块,Windows环境下也可使用ctypes.WinDLL("dll路径")。这两种方式分别等价于:ctypes.CDLL("路径") == ctypes.cdll.LoadLibrary("路径"),以及ctypes.WinDLL("路径") == ctypes.windll.LoadLibrary("路径")。需注意,Linux仅支持ctypes.CDLL和ctypes.cdll.LoadLibrary,而Windows支持上述所有方式。通常推荐使用ctypes.CDLL。此外,路径建议使用绝对路径,或明确相对层级。例如,若py文件与dll文件同目录,直接写mmp.dll会报错,应写为./mmp.dll。

加载动态模块后返回一个对象,上述示例中命名为lib,该对象即为扩展模块实例。

随后可直接通过lib调用内部函数。但为确保函数存在,通常采用反射方式获取。若函数不存在直接调用会抛出异常,而通过反射获取后可先判断存在性再执行。

以上为相关知识点介绍,如有补充请联系本站编辑。

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表