0.引言
Cython是通过将Python部分编译为C代码(即半自动生成Python扩展模块)以加速运行&优化计算的编程语言,是Python语言的超集,源代码文件的后缀为.pyx(另有.pyd后缀文件,由其他非Python的语言编写编译形成)。因此(超集的关系),也可以在.pyx/.pyd代码中直接编写纯Python代码并运行。
1.概要
目标是在工作路径下生成本小节最后的目录结构,其中名称加粗的为文件夹。
草绿色字体的为执行相关命令(见下文)后Cython自动生成的文件与文件夹,黑色字体的文件与文件夹需自己创建、编写。
my_pack文件夹可理解为用于存储自己编写的Python扩展模块,此例中是自定义命名为"hello"的模块,调用该模块的主模块是wrapper.py源代码文件。
【注】①本文是在Linux环境下测试,因此编译生成的中间文件为文件,在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__
xxx2.编写"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 --inplace3.编写主模块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的简单使用
















