python实现遗传算法实例_第8篇:Cython的面向对象--Python类 vs Cython扩展类

在Python中,一切都是对象。 具体来说是什么意思? 在最基本的层面上,一个对象具有三样东西

  • 标识(id):对象的标识将其与其他对象区分开来,并由id内置函数提供
  • 属性值(value):对象的值就是与之关联的数据,可以通过点表示法进行访问。通常,Python将对象的数据放在名为__ dict __的内部实例字典中。
  • 类型(type):对象指定该类型的对象表现出的行为。 这些行为可以通过称为方法的特殊功能进行访问。 当在对象上调用方法时,类型负责创建和销毁其对象,对其进行初始化以及更新其值。Python允许我们使用class语句在Python代码中创建新类型。

Python类型系统

v2-c0a9554135605ca051350b4d5682d918_b.jpg

我们知道Python的面向对象编程中,允许用户自定义的数据类型,在实例化Python的类对象时,该实例的属性值会保存到其内部dict中,即__ dict __属性,具有原生Python语义的类,其对象实例化前由Python解析器执行并经历如下过程(有些Python读物将这个过程步骤2到步骤4叫动态分派(Dynamic Dispatch),这里仅给出总结性的描述)

v2-57344fedfdde91c9d67cdebb718495ce_b.jpg

(首次加载序列化mashling格式的字节码)→从字节码缓存文件中解析实例属性的类型动态检查确定实例属性类型(类属性的尺寸)为其在实例化分配堆内存空间

  • 内置类型(Builtin Type):像object,list,dict,file,int float的数据类型,我们称为Python的内置数据类型,他们是通过Python的底层C接口实现的,并且默认整合到Python的运行时环境。
  • 用户定义类型(User Defined Type):在Python中通过使用关键字class定义的用户自定义数据类型。需要强调的该类型是具备Python语义的类(也就是纯Python代码定义的类),因此需要更多的开销。
  • 扩展数据类型(Extend Type):通过Pytho底层C接口定义的数据类型,例如C的关键字定义的struct,C++的关键字定义的class/struct定义的类,Cython的cdef class关键字定义的类.

不同类型的组合关系:

  • 在原生的Python代码中,不同Builtin Type(或扩展类型)以任意数量且不同类型的组合出包罗万象的User Definded Type,
  • 在原生的Python代码中 任意不同的User Defined Type的组合可以组合出规模更大的User Defined Type,组合的规模越大内存开销和实例化的时间开销就越大,并且在所有情况组合中,纯Python定义/组合的User Defined Type是最慢的。
  • 由于Builtin Type和Extend Type在C/C++底层定义并且在编译时类型静态绑定,因此初始化时绕过Python解析器的动态分派过程,直接提供高效的C级别内存分配和内存访问,因此以C/C++级别中,以任意不同的Builtin-Type或Extend Type组合出规模更大的Extend Type,性能相比User Defined Type仍然高出许多。

要直接在C/C++中实现Python的扩展类型需要开发者熟悉Python C底层接口,因此并不适合没有C/C++经验的开发者,然而Cython已经高度集成几乎所有C/C++的主流特性。能够以类似Python的语法快速定义出C/C++级别的Python扩展类型。

Cython中的扩展类

下面是一个简单的水果类,每种水果都有名称,数量,价格,Fruit类在纯Python的解析级别上定义(默认在.py文件中),当然也可以由Cython编译为C扩展

class 

纯Python代码定义中,我们Frui对象实例化的时间开销是265ns

v2-c78b5b90edec25735405b57fc6b13f8e_b.jpg

Cython编译后的Fruit2对象(类定义是一样,类名称不一样),时间开销是217ns

v2-7ceaa4b02264edc95cf286b2897689fe_b.jpg

当我们使用cython将Fruit类编译为C时,生成的类只是Python在C级别的用户自定义类型,而不是扩展类型。 当Cython将其编译为C时,它仍然可以使用所有操作的动态分派的通用Python对象来实现。 所生成的代码大量使用Python底层C应用接口,并且与使用纯Python代码定义此类时的Python解释器进行相同的调用。

  • 由于消除了解释器解读字节码的开销,因此Cython版本的Fruit类仅具有很小的性能提升。
  • 它不能从任何静态类型中受益,因为Fruit类的C实现仍然必须依靠动态分派来在运行时解析类型

v2-310032d0d723e04768482c8f71a9ab60_b.jpg

v2-9203589e7184fc568e5862300dfc6895_b.jpg

要将上面的Python类转化为C级别的扩展类,只需对Fruit类做以下代码修改

  • 使用cdef关键字修饰class关键字,就是告知Cython编译器,将类编译成C级别的扩展类型
  • 在类级别下,使用cdef关键字声明类属性,并且为类属性静态指定C数据类型,目地类实例化时是绕过Python解释其
%%

通过对Cython版本的Fruit类的类属性声明语句进行类型静态化后,我们实例化该实例的时间开销非常棒,最好的成绩是85.5ns

v2-d49f308bf51fad4d756c9010d0905b50_b.jpg

Cython编译的扩展类型比纯Python定义的用户定义类型快3倍多,比Cython编译的用户定义类型快2倍

v2-f124f71726d1daef64740e4c6cc00e38_b.jpg

目前这个Cython版本的Fruit类设计还不是最优的版本,我们以后探讨有关Cython面向对象编程中的更多内容。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值