Cython:将扩展类型序列作为另一个可以访问cdef方法的扩展类型的属性

2024-10-05 10:03:21 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我定义了下面的Cython类

cdef class Kernel:
    cdef readonly double a

    def __init__(self, double a):
        self.a = a

    cdef public double GetValue(self, double t):
        return self.a*t 

现在我想定义另一个扩展类型,它以一系列内核作为属性。比如:

^{pr2}$

但是,这不起作用。首先,我需要将Kernel[:]替换为object[:],否则我从gcc得到以下错误

‘PyObject’ has no member named ‘__pyx_vtab’

如果我使用object[:]所有的编译都很好,但是当我试图访问GetValue方法时出现了一个错误:

AttributeError: "AttributeError: "'cytest.Kernel' object has no attribute 'GetValue'" in 'cytest.Model.Run'

我想要什么

  1. cdef方法Run访问cdefcdef方法,而无需Python开销。在
  2. 键入检查内核的元素。在

我当前的解决方法

目前,我使用以下解决方案,但不满足上述要求:

cdef class Kernel:
    cdef readonly double a

    def __init__(self, double a):
        self.a = a

    cpdef public double GetValue(self, double t):
        return self.a*t 

cdef class Model:
    cdef readonly object[:] kernels
    cdef unsigned int n_kernels

    def __init__(self, object[:] ker):
        self.kernels = ker
        self.n_kernels = ker.shape[0]

    def Run(self, double t):

        cdef int i
        cdef double out=0.0

        for i in range(self.n_kernels):
            out += self.kernels[i].GetValue(t)

        return out

也就是说,我将内核类的方法声明为cpdef,这样就可以从Python访问它们并使用object[:]。在

问题

在Cython中有没有一种方法可以在不增加Python开销的情况下实现上述第1点和第2点?在

提前谢谢你的时间。在

NB:我事先不知道序列的长度。在

编辑

根据@DavidW的建议,我修改了代码如下

# module cytest
import cython

cdef class Kernel:
    cdef readonly double a

    def __init__(self, double a ):
        self.a = a

    cdef public double GetValue(self, double t):
        return self.a*t


cdef class Model:
    cdef readonly Kernel[:] kernels
    ### added this attribute 
    cdef Kernel k 
    cdef unsigned int n_kernels

    def __cinit__(self, Kernel[:] ker):
        self.kernels = ker
        self.n_kernels = ker.shape[0]

    cpdef double Run(self, double t):

        cdef int i
        cdef double out=0.0

        for i in range(self.n_kernels):
            # now i assign to the new attribute each time 
            # and access the cdef method from it
            self.k = self.kernels[i]
            out += self.k.GetValue(t)

        return out

现在它可以很好地编译和运行(比我以前的解决方法更快),即使我在访问Kernel[:]属性时仍然有一些python开销。在

我在这里给出了一个生成和调用Model的示例

import cytest
import numpy as np

ker_list = [cytest.Kernel(i*1.0) for i in range(3)]

# transform it to a numpy array
# to be able to pass it to the 'Model' constructor
ker_arr = np.array(ker_list)

# create a model instance
model = cytest.Model(ker_arr)

# call the method Run
print model.Run(1.0)

Tags: 方法runselfmodelobjectdefoutkernel

热门问题