让 Python 的属性查找具有 C 一级的性能

简介: 让 Python 的属性查找具有 C 一级的性能

前面我们介绍了静态类,静态类实例在属性查找方面比动态类要高效很多,因为静态类实例的属性是通过数组存储的,一个萝卜一个坑,访问的时候基于索引访问。但无论是静态类还是动态类,其实例在查找属性时,底层都会调用 PyObject_GetAttr 这个 C API。

那么问题来了,能不能再快一点呢?因为一旦涉及到 Python/C API,效率都是不高的,而 Python 的对象在底层都是一个 C 结构体,那么在查找属性的时候能不能直接访问 C 结构体的字段呢?不要再走 Python 的 C API 了。

我们举例说明:

cdef class Score:
    cdef public:
        int chinese, math, english
    def __init__(self, int chinese,
                 int math, int english):
        self.chinese = chinese
        self.math = math
        self.english = english
s = Score(90, 98, 92)
print(
    s.chinese, s.math, s.english
)  # 90 98 92

以上是一段 Cython 代码,如果换成功能相同的 C 代码的话:

#include <stdio.h>
typedef struct {
    int chinese;
    int math;
    int english;
} Score;
int main() {
    Score s = {90, 98, 92};
    printf("%d %d %d\n",
           s.chinese, s.math, s.english); // 90 98 92  
}

那么问题来了,我们能不能将 Cython 中的属性访问,转成 C 一级的属性访问呢?答案是可以的,下面来看一下具体的做法。

# 文件名:score.pyx
cdef class Score:
    cdef public:
        int chinese, math, english
    def __init__(self, int chinese,
                 int math, int english):
        self.chinese = chinese
        self.math = math
        self.english = english

我们需要先将 score.pyx 编译成扩展模块,编译方式很简单,这里不再赘述了。然后还要编写一个头文件 score.h:

#include <Python.h>
// 定义一个 C 结构体,模拟扩展类 Score
typedef struct {
    PyObject_HEAD
    int chinese;
    int math;
    int english;
} C_Score;

接下来再编写一个 Cython 源文件导入它:

# 文件名:cython_test.pyx
cdef extern from "score.h":
    ctypedef class score.Score [object C_Score]:
        cdef:
            int chinese
            int math
            int english
# 这里我们使用了 ctypedef class,可以简单认为导入了一个类
# 而 ctypedef class 紧跟的是 score.Score,编译器在看到之后
# 就知道要从 score 模块里导入类 Score
# 所以我们不需要 from score import Score,会自动导入
# 但是导入了还不算完,后面还跟了一个 C_Score
# C_Score 和 score.Score 里面的成员都是一样的
# 然后 Cython 编译器会生成 C 结构体字段的直接访问
# 而不会再走 Python 的 C API
def summer(Score s):
    # 进行类型声明的话,只需要使用 Score 即可
    # 并且这里的 Score 只能在 Cython 内部使用
    return s.chinese + s.math + s.english

然后进行编译,导入测试一下:

from score import Score
import cython_test
s = Score(99, 98, 97)
print(cython_test.summer(s))  # 294

结果没有任何问题,并且此时 Cython 是直接访问的结构体字段,而不是使用 __getattr__。

然后要说明的是,类的名字和 C 结构体的名字不要求相同,但是内部字段的名字应该是相同的。假设 C_Score 的字段如下

#include <Python.h>
// 定义一个 C 结构体,模拟扩展类 Score
typedef struct {
    PyObject_HEAD
    int a;
    int b;
    int c;
} C_Score;

那么声明的时候就应该这么做:

# 文件名:cython_test.pyx
cdef extern from "score.h":
    ctypedef class score.Score [object C_Score]:
        cdef:
            int chinese "a"
            int math "b"
            int english "c"

否则的话,在 C 结构体中就找不到对应的字段。当然啦,找不到的话会退化使用 __getattr__,不会报错。

此外该方法也适用于内置类型,不过用的不多,而且我们也很少使用 ctypedef class,因此本文的内容了解一下即可。

相关文章
|
2月前
|
Java 数据处理 索引
(Pandas)Python做数据处理必选框架之一!(二):附带案例分析;刨析DataFrame结构和其属性;学会访问具体元素;判断元素是否存在;元素求和、求标准值、方差、去重、删除、排序...
DataFrame结构 每一列都属于Series类型,不同列之间数据类型可以不一样,但同一列的值类型必须一致。 DataFrame拥有一个总的 idx记录列,该列记录了每一行的索引 在DataFrame中,若列之间的元素个数不匹配,且使用Series填充时,在DataFrame里空值会显示为NaN;当列之间元素个数不匹配,并且不使用Series填充,会报错。在指定了index 属性显示情况下,会按照index的位置进行排序,默认是 [0,1,2,3,...] 从0索引开始正序排序行。
233 0
|
6月前
|
机器学习/深度学习 数据采集 算法
Python AutoML框架选型攻略:7个工具性能对比与应用指南
本文系统介绍了主流Python AutoML库的技术特点与适用场景,涵盖AutoGluon、PyCaret、TPOT、Auto-sklearn、H2O AutoML及AutoKeras等工具,帮助开发者根据项目需求高效选择自动化机器学习方案。
612 1
|
8月前
|
数据采集 测试技术 C++
无headers爬虫 vs 带headers爬虫:Python性能对比
无headers爬虫 vs 带headers爬虫:Python性能对比
|
4月前
|
数据采集 存储 Web App开发
Python爬虫库性能与选型实战指南:从需求到落地的全链路解析
本文深入解析Python爬虫库的性能与选型策略,涵盖需求分析、技术评估与实战案例,助你构建高效稳定的数据采集系统。
367 0
|
4月前
|
Python
解决Python中AttributeError:'image'对象缺少属性'read_file'的问题策略。
通过上述策略综合考虑,您将能够定位问题并确定如何解决它。记住,Python社区很庞大,也很乐于帮助解决问题,因此不要害怕在求助时提供尽可能多的上下文和您已经尝试过的解决方案。
128 0
|
7月前
|
网络协议 API 开发者
分析http.client与requests在Python中的性能差异并优化。
合理地选择 `http.client`和 `requests`库以及在此基础上优化代码,可以帮助你的Python网络编程更加顺利,无论是在性能还是在易用性上。我们通常推荐使用 `requests`库,因为它的易用性。对于需要大量详细控制的任务,或者对性能有严格要求的情况,可以考虑使用 `http.client`库。同时,不断优化并管理员连接、设定合理超时和重试都是提高网络访问效率和稳定性的好方式。
162 19
|
6月前
|
网络协议 API Python
解析http.client与requests在Python中的性能比较和改进策略。
最后,需要明确的是,这两种库各有其优点和适用场景。`http.client` 更适合于基础且并行的请求,`requests` 则因其易用且强大的功能,更适用于复杂的 HTTP 场景。对于哪种更适合你的应用,可能需要你自己进行实际的测试来确定。
170 10
|
机器学习/深度学习 Python
堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能
本文深入探讨了堆叠集成策略的原理、实现方法及Python应用。堆叠通过多层模型组合,先用不同基础模型生成预测,再用元学习器整合这些预测,提升模型性能。文章详细介绍了堆叠的实现步骤,包括数据准备、基础模型训练、新训练集构建及元学习器训练,并讨论了其优缺点。
735 3
|
11月前
|
测试技术 数据库 Python
Python装饰器实战:打造高效性能计时工具
在数据分析中,处理大规模数据时,分析代码性能至关重要。本文介绍如何使用Python装饰器实现性能计时工具,在不改变现有代码的基础上,方便快速地测试函数执行时间。该方法具有侵入性小、复用性强、灵活度高等优点,有助于快速发现性能瓶颈并优化代码。通过设置循环次数参数,可以更准确地评估函数的平均执行时间,提升开发效率。
276 61
Python装饰器实战:打造高效性能计时工具
|
8月前
|
Python
解决Python报错:DataFrame对象没有concat属性的多种方法(解决方案汇总)
总的来说,解决“DataFrame对象没有concat属性”的错误的关键是理解concat函数应该如何正确使用,以及Pandas库提供了哪些其他的数据连接方法。希望这些方法能帮助你解决问题。记住,编程就像是解谜游戏,每一个错误都是一个谜题,解决它们需要耐心和细心。
375 15

推荐镜像

更多