第6篇:Cython的面向对象编程--扩展类的实例化
2020-04-22 本文已影响0人
铁甲万能狗
我们前篇谈到了Cython的访问控制,并且谈论了cdef class关键字的底层操作,顺带也谈论了Python类为什么会比Cython类慢的原因。本篇我们将介绍Cython扩展类的初始化
Cython扩展类实例实例化,C的运行时系统在内存中都为其实例持有一个C结构体的内存区域,对于对象的创建和初始化,当Python调用__ init __时,self参数必须是该扩展类型的有效实例,当调用 __ init __时,通常使用来自参数来初始化类实例属性,但在C底层,在调用 __ init __之前,必须为其扩展类型的实例分配内存,并且结构体的字段都必须处于有效状态。
__ cinit __和__dealloc __方法
__ cinit__是负责执行C级别的类实例属性(指针类型)的内存分配和初始化,并且在外部代码的执行结束前,Cython编译器会默认隐含调用扩展类实例的 __ dealloc __方法,这些行为和C++编译器是一致。
- __ cinit__等同C++类中默认构造函数
- __ dealloc__ 等同于C++类的析构函数
使用__ cinit__的注意事项
- __ cinit__可能会带来额外的开销
- __ cinit__的参数声明和__ init__必须一致,因为它们会被同时调用,因此__ cinit__的参数会留下kargs,*kwargs
- __ cinit__中涉及到C指针类型的类属性的内存分配,必须在类定中显式定义__ dealloc__,因为需要通过__ dealloc __对C指针类型的实例属性进行内存释放
- __ cinit__和__ init __只能使用def关键字申明
我们通过一些例子来列举使用 __ cinit 的情况,下面的是一个Cython扩展类Fruit,在C级别的扩展类,若定义了C指针类型的类属性,在 cinit__方法内完成C类型的类实例属性的初始化和内存分配,是其主要的用途
from libc.stdlib cimport malloc,free
cdef class Fruit(object):
'''Fruit Type'''
cdef readonly str name
cdef public double qty
cdef readonly double price
cdef double *weight
def __cinit__(self,nm,qt,pc):
print("__cinit__ method executed")
self.name=nm
self.qty=qt
self.price=pc
self.weight=<double*>malloc(sizeof(double))
self.weight[0]=23.33
print("weight: ",self.weight[0])
def __init__(self,nm,qt,pc):
print("__init__ method executed")
def amount(self):
return self.qty*self.price
def __dealloc__(self):
print("__dealloc__method executed")
if self.weight!=NULL:
free(self.weight)
调用代码
#!/usr/bin/python3
import pyximport
pyximport.install()
import cy_fruit
if __name__=='__main__':
b=cy_fruit.Fruit("banana",23.0,33.0)
b.amount()
Cython扩展类在构造时会保证__ cinit__只能被调用一次,并且在__ init__,__ new__或其他Python级别的构造函数(例如,类方法构造函数)之前被调用, Cython将所有初始化参数传递给 __ cinit __,并在./app.py的Python外部代码在结束之前,隐式调用Fruit类实例b. __ dealloc __
Cython扩展类的快速实例化
更新中....