假设我定义了以下 Cython 类
\n\ncdef class Kernel:\n cdef readonly double a\n\n def __init__(self, double a):\n self.a = a\n\n cdef public double GetValue(self, double t):\n return self.a*t \nRun Code Online (Sandbox Code Playgroud)\n\n现在我想定义另一个具有内核序列作为属性的扩展类型。就像是:
\n\ncdef class Model:\n cdef readonly Kernel[:] kernels\n cdef unsigned int n_kernels\n\n def __init__(self, Kernel[:] ker):\n self.kernels = ker\n self.n_kernels = ker.shape[0]\n\n cdef double Run(self, double t):\n\n cdef int i\n cdef double out=0.0\n\n for i in range(self.n_kernels):\n out += self.kernels[i].GetValue(t)\n\n return out\nRun Code Online (Sandbox Code Playgroud)\n\n然而,这不起作用。首先我需要替换Kernel[:]为object[:],否则我会收到以下错误gcc
\xe2\x80\x98PyObject\xe2\x80\x99 has no member named \xe2\x80\x98__pyx_vtab\xe2\x80\x99\nRun Code Online (Sandbox Code Playgroud)\n\n如果我使用一切编译正常,但在尝试访问方法object[:]时出现错误:GetValue
AttributeError: "AttributeError: "\'cytest.Kernel\' object has no attribute \'GetValue\'" in \'cytest.Model.Run\'\nRun Code Online (Sandbox Code Playgroud)\n\ncdef的方法,无需 Python 开销。KernelcdefRun目前我使用以下解决方案,但不满足上述要求:
\n\ncdef class Kernel:\n cdef readonly double a\n\n def __init__(self, double a):\n self.a = a\n\n cpdef public double GetValue(self, double t):\n return self.a*t \n\ncdef class Model:\n cdef readonly object[:] kernels\n cdef unsigned int n_kernels\n\n def __init__(self, object[:] ker):\n self.kernels = ker\n self.n_kernels = ker.shape[0]\n\n def Run(self, double t):\n\n cdef int i\n cdef double out=0.0\n\n for i in range(self.n_kernels):\n out += self.kernels[i].GetValue(t)\n\n return out\nRun Code Online (Sandbox Code Playgroud)\n\n即我将 Kernel 类的方法声明为 ,cpdef以便可以从 Python 访问它们并使用object[:].
有没有办法在 Cython 中实现上述第 1 点和第 2 点而不需要 Python 开销?
\n\n在此先感谢您的时间。
\n\n注意:我事先不知道序列的长度。
\n\n根据@DavidW的建议,我修改了代码如下
\n\n# module cytest\nimport cython\n\ncdef class Kernel:\n cdef readonly double a\n\n def __init__(self, double a ):\n self.a = a\n\n cdef public double GetValue(self, double t):\n return self.a*t\n\n\ncdef class Model:\n cdef readonly Kernel[:] kernels\n ### added this attribute \n cdef Kernel k \n cdef unsigned int n_kernels\n\n def __cinit__(self, Kernel[:] ker):\n self.kernels = ker\n self.n_kernels = ker.shape[0]\n\n cpdef double Run(self, double t):\n\n cdef int i\n cdef double out=0.0\n\n for i in range(self.n_kernels):\n # now i assign to the new attribute each time \n # and access the cdef method from it\n self.k = self.kernels[i]\n out += self.k.GetValue(t)\n\n return out\nRun Code Online (Sandbox Code Playgroud)\n\n现在它编译并运行良好(并且比我以前的解决方法更快),即使我在访问属性时仍然有一些 python 开销Kernel[:]。
我在这里举了一个构建和调用的示例Model
import cytest\nimport numpy as np\n\nker_list = [cytest.Kernel(i*1.0) for i in range(3)]\n\n# transform it to a numpy array\n# to be able to pass it to the \'Model\' constructor\nker_arr = np.array(ker_list)\n\n# create a model instance\nmodel = cytest.Model(ker_arr)\n\n# call the method Run\nprint model.Run(1.0)\nRun Code Online (Sandbox Code Playgroud)\n