问题 使用其他Cython代码中的自定义Cython代码


我目前正在尝试优化我的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 预先 - 根据 文档(早期绑定速度) 是必要的,以消除函数调用开销。我尝试了以下,但不起作用:

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

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

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

谢谢和最好的问候!


9772
2018-03-16 19:56


起源

我想知道问题是什么,所以如果有问题请留意我们! - highBandWidth
我意识到这是一个古老的问题,但我现在遇到了一个非常类似的问题。你有没有想过这个? - user27886
不幸的是,我从来没有解决过这个问题,因为在某些时候这部分代码与我的项目无关。无论如何,我祝你好运,如果你弄清楚,把它贴在这里,我很乐意接受它作为正确的答案。 - packoman
经过大量的搜索,我发现了这个完美的答案: stackoverflow.com/questions/33616927/... - Davoud Taghawi-Nejad


答案:


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

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

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

bendingForcesClass .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 文件:

bendingForcesClass .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模块中导入,使其成为有效的类型标识符,这可以解决您的问题。


6
2018-05-26 13:25





您需要使用声明“.pxd”文件和cimport。 (基本上,cimport在编译时发生,而导入发生在运行时,因此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:在类型声明中使用导入的类


4
2018-05-26 13:51





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

可能是你正在使用 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


2
2018-03-18 15:12



由于编辑原始问题以使用PEP8,这个答案有点不同步;对于那个很抱歉。 - Erik Allik