博主近期因为项目中暴露的性能问题,需要为python编写一个c++的扩展,以达到提高运行效率的目的,故借此机会了解了利用python自带的C类库来编写C/C++扩展的具体实现方法,在此记录一下。
这里使用的python版本为3.10.2, 使用的是vs build tool 2022提供的msvc进行编写
本文使用的vscode和vs build tool 2022来实现环境的搭建,这里默认已经安装好了mscv以及vscode的c++相关插件。
首先新建一个文件夹,作为工作空间,并在其中新建一个source文件夹用于存放源代码,一个build文件夹用来存储编译之后的结果。
打开开始菜单,找到vs2022的文件夹,并选择对应版本的控制台打开。(选择X86还是X64版本的控制台取决于python的版本,这里务必保持和python一致。博主使用的是x64版本的python,故打开对应的x64版本控制台)在打开控制台之后,将路径切换到刚刚创建好的工作空间目录下,输入"code ."打开vscode。
在source文件夹下新建一个main.cpp文件,并写入一个简单的hello world程序,用于之后的测试
点击F5运行代码,会看到vscode出现弹窗。我们使用的是msvc,因此应该选择C++(windows)
之后的一个弹窗选择cl.exe
可以看到运行的结果,说明我们msvc配置成功了
由于本文涉及的内容并没有调试的过程,因此此处不再演示如何进行debug,若读者有这方面的需求,可以参考vscode官网的c++文档,里面有更为详细的过程
此时可以看的工作空间的目录下,vscode自动生成了一个task.json配置文件(如下图所示)
其中args数组中是cl的配置项,目前是最基础的配置,如果需要编写python的扩展,那么还需要对其进行调整,这里我直接展示调整之后的task.json文件
这里介绍一下对应的修改项以及其意义
将参数调整好之后,便可以开始进行编码了。这里附上python官方提供的原版教程以供参考。本文用一个简单的案例来演示,先上代码。
#include
#include
int Add(int x, int y){
return x + y;
}
void Print(char* str){
std::cout<
先简单写两个函数,一个实现加法,一个实现打印。为了让python可以识别,需要对它们使用Python.h提供的PyObject来封装。
每个返回PyObject的函数都有两个固定参数,self和args。函数中的PyArg_ParseTuple用来将python形式的参数映射为C类型的数据。函数的返回值可以使用Py_BuildValue进行封装,以转换成python可以识别的类型。这里需要注意的是,如果函数没有任何需要返回的值,那么需要让函数返回None,具体方式见py_print()函数。
在函数封装完毕后,将方法打包进PyMethodDef结构体中,这个结构体数组中每一项的四个值分别对应:
将全部函数打包好之后,便可以开始打包模型了,也就是代码中的PyModuleDef,这里比较重要的是第二个值,这个值是模块的名称。
最后编写PyInit函数用来生成之前打包好的模组,此处的格式较为固定,需要注意的是PyInit_name()中,name是打包模组的名称,python在第一次执行我们打包的模块时会调用这个函数。在编写好全部代码后,使用快捷键"shift+ctrl+B"编译代码。
上述代码中有一点会出现问题,及python.h可能不能被识别到,此时需要添加c/c++语言配置文件,并将python.h所在的路径添加到其中的includePath中
在编译链接之后,build文件夹下应该会有若干文件生成,如下图
其中dll动态链接库就是打包好的C++扩展,不过python不能直接识别dll文件,需要先将其重命名为.pyd格式,再使用import进行引入。
下面调用模型的接口进行测试
import mymodule as md
md.my_print("hello world")
print(md.my_add(1, 1))
本文为本人的学习笔记,如有问题欢迎指出和讨论@茱莉亚之歌