2022spring——Cython入坑篇
0.引言
Cython是通过将Python部分编译为C代码(即半自动生成Python扩展模块)以加速运行&优化计算的编程语言,是Python语言的超集,源代码文件的后缀为.pyx(另有.pyd后缀文件,由其他非Python的语言编写编译形成)。因此(超集的关系),也可以在.pyx/.pyd代码中直接编写纯Python代码并运行。
1.概要
目标是在工作路径下生成本小节最后的目录结构,其中名称加粗的为文件夹。
草绿色字体的为执行相关命令(见下文)后Cython自动生成的文件与文件夹,黑色字体的文件与文件夹需自己创建、编写。
my_pack文件夹可理解为用于存储自己编写的Python扩展模块,此例中是自定义命名为"hello"的模块,调用该模块的主模块是wrapper.py源代码文件。
【注】①本文是在Linux环境下测试,因此编译生成的中间文件为xxx.so文件,在windows下生成的中间文件格式不同,此处略过;
②使用Cython的准备工作——安装Cython库的操作较为简单(官网下载or pip命令安装),本文不做介绍。
pwd/
|
|——my_pack
|——hello.pyx
|——setup.py
|——hello.c
|——hello.cpython-xxx-linux-gnu.so
|——build
|——xxx
|——__pycache__
|——xxx
|——wrapper.py
|——__pycache__
|——xxx
2.编写"hello"模块
首先在终端执行如下两行命令,进入新创建的my_pack目录下:
> mkdir my_pack > cd my_pack
创建如下hello.pyx文件:
1 # file: my_pack/hello.pyx 2 # coding=utf-8 3 def print_hello(name): 4 print("Hello %s!" % name)
创建与之配套的setup.py文件,如下:
1 # file: my_pack/setup.py 2 # cython: language_level=3 3 4 from distutils.core import setup 5 from distutils.extension import Extension 6 from Cython.Distutils import build_ext 7 8 my_modules = [Extension("hello", ["hello.pyx"])] 9 setup( 10 name = "Hello_any_name", 11 cmdclass = {'build_ext': build_ext}, 12 ext_modules = my_modules 13 )
【说明】①此处编写的my_modules就是自定义的Python扩展模块,注意这里的模块名称必须与源代码文件的名称相同、否则会报错,详见stackoverflow讨论;
②setup(name=...)的name似乎并不重要,只是方便后续(可能的)调试,可以随意命名这一模块,只要体现该模块功能即可;
③本文件第二行指定Python语言级别为3(Python3),默认值为2(Python2),若未自定义语言级别、可能会在终端首次运行setup.py时出现警告(但一般不重要);
④setup.py文件除了上述写法,似乎也可以使用Cython库某一模块中的cythonize代替build_ext,未作深入研究,此处略过。
接着执行如下编译命令,即可生成本文第一小节所示的my_pack目录结构下的所有文件:
【提示】如果在执行编译命令时出现错误,最好先完全删除由编译命令生成的文件、修改上文自定义的文件源代码,再重新执行编译命令
> python setup.py build_ext --inplace
3.编写主模块wapper.py
先返回上层工作目录:
> cd ..
创建如下wrapper.py文件:
1 # file: wrapper.py 2 #!/usr/bin/python 3 # coding = utf-8 4 5 from my_pack import hello 6 if __name__ == "__main__": 7 hello.print_hello("my 1st Cython code")
在终端运行此文件即可:
> python wrapper.py
> Hello my 1st Cython code!
4.Python的模块概念
4.1 注意Cython生成的模块的“封装性”
调用Cython生成的Python扩展模块的.py文件只能访问.pyx文件中定义的类或直接调用.pyx中的函数,无法使用.pyx中函数的返回值或定义的局部变量。
以博主的经验、目前猜测.pyx中的函数返回值在.py中均为NoneType,具体原因未作深究。
【注】Cython的完整/深入使用应该是Python代码与类C代码的结合,即只在入口出口处使用Python代码、在I/O密集或计算密集处使用类C代码,限于博主目前的了解有限与篇幅,本文暂不做介绍。感兴趣者可以自行搜索关键词“Cython cdef”了解。
4.2 Python模块的定义与标识
博主查阅资料时,发现有资料中提出要在my_pack文件夹下创建__init__.py文件(内容为from hello import *)并将外层的主模块wrapper.py命名为hello.py,以便调用my_pack路径中的模块。但这么做之后,实际上外层的hello.py会被作为其他模块import一次、作为主模块运行一次,比较混乱。博主没有采用这种写法,目前也没发现任何问题。
以下是查阅到的介绍Python模块概念的部分资料,仅供参考:
后记
主要参考资料:Cython的简单使用
posted on 2022-02-22 14:53 Mju_halcyon 阅读(106) 评论(0) 编辑 收藏 举报
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构