利用Cython将Python算法封装为动态链接库(DLL)的完整指南

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

本文详解如何将Python算法封装为Windows动态链接库(DLL)以供其他语言调用。通过Cython将Python脚本转换为C代码,结合Visual Studio编译器生成DLL,并解决Python环境依赖问题。文章提供从代码转换、编译命令到使用PyInstaller打包依赖包的完整步骤,帮助开发者实现高效的跨语言算法集成。

Python在深度学习中的地位与动态库价值

随着深度学习技术的迅猛发展,Python已确立其在深度学习研究领域的核心地位。绝大多数主流深度学习框架均提供Python接口,众多关键算法也实现了Python版本。为了将这些算法落地应用于实际工程项目,各类工具包提供了多种类型的接口支持。

动态链接库(Windows下为.dll,Linux下为.so)是系统开发中实现跨语言协作的关键机制。将Python编写的算法编译为动态库,可允许其他编程语言调用,从而显著提升算法的开发与集成效率。

使用Cython将Python转换为C代码

尽管Python能够调用由其他语言生成的动态库,但作为一种脚本语言,Python本身不具备直接编译生成动态库的能力。为实现动态库的生成,我们需要借助Cython工具,将Python脚本转换为C语言代码。下文将通过一个具体示例演示这一过程。


def str_add(str1,str2): 
    return int(str1) + int(str2)

该示例代码的功能是将两个数字字符串转换为整数并计算其和。我们将此代码保存为run.py以备后续使用。根据Cython的语法规范,我们编写对应的Cython版本函数:


cdef public str_add(str1,str2):
     return int(str1) + int(str2)

与原始Python版本相比,此处使用cdef替代def,并添加public关键字,表明该函数需要被导出。将此代码保存为pyx文件,例如run.pyx。

接下来,执行以下命令将pyx文件转换为C语言版本:

cython run.pyx

执行上述命令后,目录下会生成run.h和run.c两个文件。这两个文件通过调用Python的C API实现了run.py中定义的功能。

编写DLL主文件并编译生成

随后,我们编写动态库的主文件dllmain.c:


#include <Python.h>
#include <Windows.h>
#include "run.h"
 
extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b) {
  return PyLong_AsLong(str_add(PyUnicode_FromString(a),PyUnicode_FromString(b)));<br data-filtered="filtered">
}
 
BOOL WINAPI DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpReserved) {
  switch( fdwReason ) {
    case DLL_PROCESS_ATTACH:
      Py_Initialize();
      PyInit_run(); #dll初始化的时候调用,这是python3的写法,python2改成,initrun()。参见生成的run.h
      break;
    case DLL_PROCESS_DETACH:
      Py_Finalize();
      break;
  }
  return TRUE;
}

该文件定义了导出函数_str_add。在Python中,所有数据均以PyObject类型存储。此函数通过PyUnicode_FromString将两个字符串转换为Python对象,调用run.h中的str_add函数进行求和,最后通过PyLong_AsLong将结果从Python对象转换回C语言的整型数字。

我们可以通过以下命令将代码编译生成DLL:

cl /LD dllmain.c run.c -IC:\python36\include C:\python36\libs\python36.lib

请注意,上述命令中的Python路径需根据您计算机上Python的实际安装位置进行相应调整。

生成DLL后,我们编写一个简单的测试程序来验证其功能:


#include "stdio.h"
#include "stdlib.h"
extern __declspec(dllexport) int __stdcall _str_add(const char * a, const char * b);
 
#pragma comment(lib,"dllmain.lib")
 
int main()
{
 printf("%d \n", _str_add("123","456"));
 return 0;
}

输出结果为:579,这正好等于123加456的结果。

使用PyInstaller处理依赖包打包

通过上述步骤,我们成功将Python代码实现的功能封装为动态库。然而,该DLL无法在未安装Python的环境中运行。事实上,Python代码通常依赖多个第三方包才能正常运行,且不同代码所需的依赖包各不相同。为了解决依赖包查找问题,我们引入另一个工具PyInstaller。具体步骤简述如下:

virtualenv envpack # 创建新的虚拟环境,由于Python包依赖关系复杂,创建新环境有助于减少最终引入的冗余包 cd envpack # 进入目录 # 将run.py复制到此目录,run.py运行所需的包与最终DLL所需的包一致 Scripts\activate # 激活并切换到virtualenv环境 pip install pyinstaller # 安装打包工具PyInstaller pip install numpy # 安装脚本所需的库(如numpy),请根据import语句检查所需库 pyinstaller run.py # 执行打包命令 Scripts\deactivate # 打包成功后,使用命令取消激活环境 需要打包的文件位于envpack\dist目录下,包含多个.dll和.pyd文件,将这些文件与生成的DLL一同发布即可。

总结

至此,关于使用Python创建生成动态链接库DLL的方法介绍完毕。如需了解更多Python动态链接库DLL相关内容,请搜索本站过往文章或继续浏览相关文章。希望本文对大家有所帮助,欢迎继续支持本站!

相关标签:

本站声明

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

Python 相关产品和应用

全部下载

专题列表