12

我目前正在尝试优化我的 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 类中,我调用了 class-method calculate,因此在我的组合类中,我有以下(简化的)代码:

from bendingForcesClass import bendingForcesClass

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

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

我发现这cpdef使得方法/函数可以从 Python 和 Cython 调用,这很好并且有效,只要我不尝试self.bendingForces预先定义类型 - 根据文档(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)

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

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

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

那么我该怎么做呢?如果有人能给我指点,我将非常感激,因为除了上面给出的链接之外,我找不到任何关于此的信息。

谢谢和最好的问候!

4

3 回答 3

7

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

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

对于您的示例,您需要一个文件bendingForcesClass.pxd,它声明您要共享的类,以及所有 cimport、模块级变量、typedef 等:

弯曲力 类 .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文件中删除:

弯曲力 类 .pyx
import numpy as np

cdef class bendingForcesClass(object):

    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

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

于 2017-05-26T13:25:50.713 回答
4

您需要使用声明“.pxd”文件和 cimport。(本质上,cimport 发生在编译时,而 import 发生在运行时,因此 Cython 无法使用任何重要的东西)。

创建“utils.pxd”:

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

“utils.pyx”现在读取

cdef class MyClass:
    def __init__(self, field):
    self.field = field

cdef void go(self, int i):
    self.field = i

pyx 文件中的所有声明都进入 .pxd 文件。

然后在 mymodule.pyx

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

// 此处的扩展答案: Cython:在类型声明中使用导入的类

于 2017-05-26T13:51:29.800 回答
2

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

可能是您在bendingForces这里用作变量的名称:

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

以及这里的成员对象的名称:

cdef class membraneClass( object ):
    cdef bendingForcesClass bendingForces

此外,bendingForcesClass是模块的名称以及类。最后,如何ctypedef从课堂上制作一个bendingForcesClass

于 2011-03-18T15:12:48.053 回答