Cython 的宏定义

简介: Cython 的宏定义

我们知道在 C 里面可以使用 #define 定义一个宏,这在 Cython 里面也是可以的,不过使用的是 DEF 关键字。

DEF NUMBER = 123
DEF NAME = "古明地觉"
print(NUMBER)
print(NAME)
"""
123
古明地觉
"""

DEF 定义的宏在编译的时候会被替换成我们指定的值,但是需要注意:宏对应的值必须在编译的时候就能确定,我们不能给宏赋一个运行时才能构建的值。举个例子:

DEF ARRAY = [1, 2, 3, 4]
print(ARRAY)

这行代码编译时会报错,因为列表需要运行时动态构建.


但元组是可以的,因为元组在编译的时候就会作为一个常量加载进来。

DEF ARRAY = (1, 2, 3, 4)
print(ARRAY)  # (1, 2, 3, 4)

另外我们知道 C 里面的宏是可以带参数的,但在 Cython 里面不支持。所以在 Cython 里面使用宏的话,替换的一般都是数值、字符串之类的

在 C 里面还可以使用 IF ELIF ELSE 进行条件编译,Cython 也是支持的。

DEF SYSNAME = "Windows"
IF SYSNAME == "Windows":
    print("这是 Windows")
ELIF SYSNAME == "Darwin":
    print("这是 Mac OS")
ELIF SYSNAME == "Linux":
    print("这是 Liunx")
ELSE:
    print("其它类型的系统")

该文件在编译之后实际上只有两行:

DEF SYSNAME = "Windows"
print("这是 Windows")

当不同的系统,需要执行不同的逻辑时,IF ELIF ELSE 就很有用。为此,Cython 提供了几个预定义的宏,专门用于判断操作系统类型。

  • UNAME_SYSNAME:操作系统的名称;
  • UNAME_RELEASE:操作系统的发行版;
  • UNAME_VERSION:操作系统的版本;
  • UNAME_MACHINE:操作系统的机型、或者硬件名称;
  • UNAME_NODENAME:网络名称;


IF UNAME_SYSNAME == "Windows":
    print("这是 Windows")
ELIF UNAME_SYSNAME == "Darwin":
    print("这是 Mac OS")
ELIF UNAME_SYSNAME == "Linux":
    print("这是 Liunx")
ELSE:
    print("其它类型的系统")
"""
这是 Windows
"""

这些宏都是预定义好的,但必须搭配 IF ELIF ELSE 使用,否则报错。


阶段性小结




到目前为止,我们深入介绍了 Cython 的语言特性,并且为了更好地理解,我们使用了很多 CPython 解释器里面才出现的术语,比如:PyObject、PyFunctionObject 等等。在学习 Cython 的某些知识时相当于站在了解释器的角度上,当然也介绍了 CPython 解释器的一些知识。

我们后续将会以这些特性为基础,进行深入地使用。

Cython是一个辅助语言,它是建立在 Python 之上的,为 Python 提供扩展模块。但程序的性能瓶颈,一般是由百分之二十的代码决定的,所以很少有项目会完全使用 Cython 编写(uvloop 例外),但它确实是一个成熟的语言,有自己的语法(个人非常喜欢,觉得设计的真酷)。在 GitHub 上搜索,会发现大量的 Cython 源文件分布在众多的存储库中。

考虑到 numpy, pandas, scipy, sklearn 等知名模块内部都在使用,所以 Cython 也算是被数百万的开发人员、分析师、工程师和科学家直接或者间接使用。

如果 Pareto 原理是可信的,程序中百分之 80 的运行时开销是由百分之 20 的代码引起的,那么对于一个 Python 项目来说,只需要将少部分 Python 代码转换成 Cython 代码即可。

另外我们发现,用到 Cython 的顶尖项目都与数据分析和科学计算有关,这并非偶然。Cython 之所以会在这些领域大放异彩,有以下几个原因:

1)Cython 可以高效且简便地封装现有的 C, C++, FORTRAN 库,从而对那些已经优化并调试过的功能进行访问。这里多提一句,FORTRAN算是一个上古的语言了,它的历史比 C 还要早,不过别看它出现的早、但速度是真的快,尤其是在数值计算方面甚至比 C 还要快。

包括 numpy 使用的 blas 内部也用到了 FORTRAN,虽然 FORTRAN 编写代码异常的痛苦,但是它在一些学术界和工业界还是具有一席之地的。原因就是它内部的一些算法,都是经过大量的优化、并且久经考验的,直接拿来用就可以。而 Cython 也提供了相应的姿势来调用 FORTRAN 已经编写好的功能。

2)当转化为静态类型时,内存和 CPU 密集的 Python 计算会有更好的执行性能。

3)在处理大型的数据集时,与 Python 内置的数据结构相比,在低级别控制精确的数据类型和数据结构可以让存储更高效、执行性能更优秀。

4)Cython 可以和 C, C++, FORTRAN 库共享同类型的连续数组,并通过 numpy 的数组直接暴露给 Python。

虽说用到 Cython 的一些顶尖项目都是和数据科学相关的,但即便不是在数据分析和科学计算领域,Cython 也可以大放异彩,因为它还能加速一般的 Python 代码,包括数据结构密集型算法。例如:lxml 这个高性能的 xml 解析器内部就大量使用了 Cython。因此即使它不在科学计算和数据分析的保护伞下,也依旧有很大的用途。

相关文章
|
5月前
函数库头文件问题
函数库头文件问题
|
2月前
|
存储 自然语言处理 程序员
【C语言】文件的编译链接和预处理
【C语言】文件的编译链接和预处理
|
5月前
|
安全 编译器 程序员
C语言(16)----预处理中的宏以及预处理指令
C语言(16)----预处理中的宏以及预处理指令
44 2
|
5月前
|
自然语言处理 编译器 Linux
C语言进阶⑳(程序环境和预处理)(#define定义宏+编译+文件包含)(下)
C语言进阶⑳(程序环境和预处理)(#define定义宏+编译+文件包含)
45 0
|
5月前
|
程序员 编译器 C语言
C语言进阶⑳(程序环境和预处理)(#define定义宏+编译+文件包含)(中)
C语言进阶⑳(程序环境和预处理)(#define定义宏+编译+文件包含)
38 0
|
5月前
|
存储 程序员 编译器
C语言进阶⑳(程序环境和预处理)(#define定义宏+编译+文件包含)(上)
C语言进阶⑳(程序环境和预处理)(#define定义宏+编译+文件包含)
42 0
|
5月前
|
存储 C++
c/c++宏定义(函数)
c/c++宏定义(函数)
|
5月前
|
算法 Serverless C语言
CMake函数和宏(function和macro):使用函数和宏提高代码可读性
CMake函数和宏(function和macro):使用函数和宏提高代码可读性
100 1
|
5月前
|
算法 C++ 开发者
【C/C++ 基础】条件编译相关的预编译指令
【C/C++ 基础】条件编译相关的预编译指令
41 0
|
11月前
|
编译器 C语言
C语言宏定义与条件编译
C语言宏定义与条件编译