使用来自其他Cython代码的自定义Cython代码

2024-09-28 22:36:02 发布

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

我目前正在尝试优化我的Python程序,并开始使用Cython,以减少函数调用开销,也许以后还会包括优化的C库函数。在

所以我遇到了第一个问题:

我在代码中使用合成来创建一个更大的类。到目前为止,我已经将一个Python类转换为Cython(这已经足够困难了)。代码如下:

import numpy as np
cimport numpy as np
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

cdef class bendingForcesClass(object):
    cdef dtype_t bendingRigidity
    cdef np.ndarray matrixPrefactor
    cdef np.ndarray bendingForces

    def __init__(self, dtype_t bendingRigidity, np.ndarray[dtype_t, ndim=2] waveNumbersNorm):
        self.bendingRigidity = bendingRigidity
        self.matrixPrefactor = -self.bendingRigidity * waveNumbersNorm ** 2

    cpdef np.ndarray calculate(self, np.ndarray membraneHeight):
        cdef np.ndarray bendingForces
        bendingForces = self.matrixPrefactor * membraneHeight
        return bendingForces

在我编写的Python/Cython类中,我调用了类方法calculate,因此在我的组合类中我有以下(简化的)代码:

^{pr2}$

我发现cpdef使方法/函数可以从Python和Cython调用,这很好而且很有效,只要我不尝试预先定义self.bendingForces的类型,根据the documentation (Early Binding For Speed)这是必要的,以便消除函数调用开销。我尝试了以下方法,但没有效果:

from bendingForcesClass import bendingForcesClass
from bendingForcesClass cimport bendingForcesClass

    cdef class membraneClass(object):
        cdef bendingForcesClass bendingForces

        def  __init__(self, systemSideLength, lowerCutoffLength, bendingRigidity):
            self.bendingForces = bendingForcesClass(bendingRigidity, self.waveNumbers.norm)

        def calculateForces(self, heightR):
            return self.bendingForces.calculate(heightR)

在尝试用Cython构建membraneClass.pyx时,我得到了一个错误:

membraneClass.pyx:18:6: 'bendingForcesClass' is not a type identifier
building 'membraneClass' extension

请注意,声明位于两个单独的文件中,这使得这一点更加困难。在

所以我该怎么做?如果有人能给我一个指针,我会非常感谢,因为除了上面给出的链接之外,我找不到任何关于这个的信息。在

谢谢并致以诚挚的问候!在


Tags: 代码selfdefnpcythonndarraycalculatedtype
3条回答

这些可能不是错误的来源,但为了缩小问题的范围,您可以尝试更改以下内容:

可能是您在这里使用bendingForces作为变量名:

cpdef np.ndarray calculate( self, np.ndarray membraneHeight ) :
      cdef np.ndarray bendingForces
      bendingForces = self.matrixPrefactor * membraneHeight
      return bendingForces

这里还有成员对象的名称:

^{pr2}$

另外,bendingForcesClass是模块和类的名称。最后,从类bendingForcesClass生成一个ctypedef怎么样?在

您需要使用声明“.pxd”文件和cimport。(本质上,cimport发生在编译时,而导入发生在运行时,所以Cython不能利用任何重要的东西)。在

Create "utils.pxd":

cdef class MyClass:
    cdef readonly int field
    cdef void go(self, int i)

"utils.pyx" now reads

^{pr2}$

pyx文件中的所有声明都将放入.pxd文件中。在

Then in mymodule.pyx

from utils import MyClass
from utils cimport MyClass
# other code follows...

//从这里扩展答案: Cython: using imported class in a type declaration

免责声明:这个问题非常古老,我不确定当前的解决方案是否适用于2011年Cython代码。在

为了从另一个文件cimport一个扩展类(cdef类),您需要提供一个声明所有C类、属性和方法的.pxd文件(也称为定义文件)。请参阅文档中的Sharing Extension Types以供参考。在

例如,您需要一个文件bendingForcesClass.pxd,该文件声明要共享的类,以及所有cimports、模块级变量、typedef等:

弯曲力class.pxd
# cimports
cimport numpy as np

# typedefy you want to share
ctypedef np.float64_t dtype_t
ctypedef np.complex128_t cplxtype_t
ctypedef Py_ssize_t index_t

cdef class bendingForcesClass:
    # declare C attributes
    cdef dtype_t bendingRigidity
    cdef np.ndarray matrixPrefactor
    cdef np.ndarray bendingForces

    # declare C functions
    cpdef np.ndarray calculate(self, np.ndarray membraneHeight)

    # note that __init__ is missing, it is not a C (cdef) function

现在在.pxd文件中声明的所有导入、变量和属性都可以(并且必须)从.pyx文件中删除:

弯曲力class.pyx ^{pr2}$

现在您的cdef类bendingForcesClass可以从其他Cython模块cimported,使其成为有效的类型标识符,这应该可以解决您的问题。在

相关问题 更多 >