预定义的 .pxd 文件

简介: 预定义的 .pxd 文件


libc




之前我们使用了这样一条导入语句:from libc.stdlib cimport malloc,显然这是 Cython 提供的预定义 .pxd 文件,位于 Cython 主目录的 Includes 目录中。

C 的头文件在 Cython 里面是以 .pxd 文件的形式存在的,所以这个目录相当于包含了常用的 C 头文件。当然这些都只是声明,至于具体实现则隐藏在编译器当中,我们看不到罢了。

from libc cimport stdio
stdio.printf(<char *>"name = %s, age = %d\n",
             <char *>"satori", <int> 16)
"""
name = satori, age = 16
"""

在 C 里面 #include <stdio.h> 之后,可以直接使用 printf,但是在 Cython 里面则需要通过 stdio.printf 的形式。这是由 Python 的命名空间决定的,因为 printf 位于 stdio 里面,在属性查找时必须先找到 stdio,然后才能找到 printf。

或者使用 from libc.stdio cimport printf 直接将某个具体的函数导入进来也行,这样就能直接使用 printf 了。当然啦,我们也可以 cimport *,这样就和 C 的 #include 一致了。

另外在导入的时候,记得名字不要冲突:

from libc.math cimport sin
from math import sin
"""
from libc.math cimport sin
from math import sin
                ^
------------------------------------------------------------
cython_test.pyx:2:17: Assignment to non-lvalue 'sin'
"""

显然导入的两个函数重名了,因此 Cython 引发了一个编译错误。而为了修复这一点,我们只需要这么做。

from libc.math cimport sin as c_sin
from math import sin as py_sin
print(c_sin(3.1415926 / 2))
print(py_sin(3.1415926 / 2))
"""
0.9999999999999997
0.9999999999999997
"""

此时就没有任何问题了。

另外导入函数的时候不可以重名,但如果我们导入的是模块的话,那么是可以重名的。

from libc cimport math
import math
print(math.sin(math.pi / 2))
"""
1.0
"""

尽管 import math 是在下面,但是调用的时候会从 C 标准库中进行调用。不过这种做法总归是不好的,我们应该修改一下:

from libc cimport math as c_math
import math as py_math

所以这些预定义的 .pxd 文件就类似于 C 的头文件:

  • 它们都声明了 C 一级的数据结构供外界调用;
  • 它们都允许开发者对功能进行拆分, 分别通过不同的模块实现;
  • 它们都实现了公共的 C 级接口;


至于每个文件里面都可以使用哪些函数,可以点进源码中查看:

关于这部分语法下一篇文章会说,总之可以看到和 C 的标准库是一致的,只不过声明的方式不同,一个是 C 的语法,一个是 Cython 的语法。但我们知道 Cython 代码也是要翻译成 C 代码的,所以 from libc cimport stdlib 最终也会被翻译成 #include <stdlib.h>

并且 Includes 目录下除了 libc 之外,还有其它的包:

其中 libcpp 里面包含了 C++ 标准模板库(STL)容器的声明,如:string, vector, list, map, pair, set 等等。而 cpython 则可以让我们访问 Python/C API,当然还有一个重要的包就是 numpy,Cython 也是支持的。


访问 Python/C API




我们来看看如何通过 Cython 来访问 Python/C API。

from cpython.list cimport (
    PyList_SetItem,
    PyList_GetItem
)
cdef list names = ["古明地觉"]
# names[0] = "古明地恋" 等价于如下
PyList_SetItem(names, 0, "古明地恋")
print(names)
"""
['古明地恋']
"""
# print(names[0]) 等价于如下
# 由于 PyList_GetItem 返回的是 PyObject *
# 我们需要转成 object
# PyObject * 是 C 层面的, object 是 Python 层面的
print(<object>PyList_GetItem(names, 0))
"""
古明地恋
"""
from cpython.object cimport (
    PyObject_RichCompareBool,
    Py_LT, Py_LE, Py_EQ,
    Py_NE, Py_GT, Py_GE
)
# 2 < 1 等价于如下
print(
    PyObject_RichCompareBool(2, 1, Py_LT)
)  # False
# 2 > 1 等价于如下
print(
    PyObject_RichCompareBool(2, 1, Py_GT)
)  # True
from cpython.object cimport (
    PyObject_IsInstance,
    PyObject_IsSubclass
)
# isinstance(123, int) 等价于如下
print(
    PyObject_IsInstance(123, int)
)  # True
# issubclass(int, object) 等价于如下
print(
    PyObject_IsSubclass(int, object)
)  # True

Python 的操作都可以通过 Python/C API 来实现,并且这种方式的速度要稍微快那么一点点。但是很明显会比较麻烦,使用 names[0] 肯定比 PyList_GetItem 这种方式来的直接,如果你还对其它的 API 感兴趣,也可以进入源码中查看。

想查看哪个对象的 API,就直接去对应的文件里面找即可。然后在导入的时候,可以直接通过 cpython 来导入,因为其它 .pxd 文件的内容都被导入到 __init__.pxd 里面了。

这个 __init__.pxd 和 __init__.py 类似,import 一个包会自动查找内部的 __init__.py,而 cimport 一个包会自动查找内部的 __init__.pxd。


小结




C、C++ 头文件通过 #include 命令进行访问,该命令会对相应的头文件进行包含。而 Cython 的 cimport 更智能,也更不容易出错,我们可以把它看做是一个使用命名空间的编译时导入语句。

而早期的 Cython 没有 cimport 语句,只有一个在源码级对文件进行包含的 include 语句,但是有了 cimport 之后就更加智能了

E N D


相关文章
|
Oracle Java 关系型数据库
Linux环境安装配置JDK11
Linux环境安装配置JDK11
1368 0
|
7月前
|
API Python
利用openvino模型推理图片
本文介绍了如何使用 OpenVINO 格式模型文件对图片进行推理。通过将训练好的模型转换为 OpenVINO 格式,可实现跨设备部署。文中详细展示了利用 Python 和 OpenVINO API 完成模型加载、编译及推理的步骤。核心代码包括初始化 OpenVINO 模型、设置预测参数(如置信度和 IoU 阈值)以及对图片进行检测并显示结果。注意:OpenVINO 模型文件需完整存放于同一目录下,路径需正确配置,参数可根据模型性能调整。
|
存储 安全 数据安全/隐私保护
Docker进阶:网络配置与服务编排
【10月更文挑战第17天】随着微服务架构的流行,Docker作为容器化技术的领导者,在企业级应用部署中扮演着重要角色。掌握Docker的高级特性,特别是网络配置和服务编排,对于构建高效、可维护的分布式系统至关重要。本文将深入探讨Docker的网络配置选项、容器间通信机制、端口映射技术以及使用Docker Compose进行多容器应用部署的最佳实践。
334 8
|
开发者 Python
Cython 的异常处理
Cython 的异常处理
156 1
|
存储 编译器 Linux
Cython 和 Python 的区别
Cython 和 Python 的区别
446 0
|
C语言 C++ Python
在 Cython 中声明结构体、共同体、枚举
在 Cython 中声明结构体、共同体、枚举
230 0
|
Rust 编译器 C++
使用 def、cdef、cpdef 创建函数
使用 def、cdef、cpdef 创建函数
309 0
|
存储 Python
Cython 中的类型转换
Cython 中的类型转换
211 0
|
JSON API 数据安全/隐私保护
Django 后端架构开发:JWT 项目实践与Drf版本控制
Django 后端架构开发:JWT 项目实践与Drf版本控制
468 0
|
编译器 C++
vs2017下原子操作和互斥锁性能比较
vs2017下原子操作和互斥锁性能比较
180 0