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模块概念的部分资料,仅供参考:

Python __init__.py文件的作用

后记

主要参考资料:Cython的简单使用

(附)Cython官方文档

posted on   Mju_halcyon  阅读(106)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

导航

统计

点击右上角即可分享
微信分享提示