【问题标题】:Using self-defined Cython code from other Cython code使用来自其他 Cython 代码的自定义 Cython 代码
【发布时间】:2011-07-16 21:43:09
【问题描述】:

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

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 的类型 - 根据 @ 987654321@ 是必要的,以消除函数调用开销。我尝试了以下方法,但不起作用:

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

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

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

谢谢和最好的问候!

【问题讨论】:

  • 我想看看问题出在哪里,如果有问题请及时通知我们!
  • 我意识到这是一个老问题,但我现在遇到了一个非常相似的问题。你有想过这个吗?
  • 没有。不幸的是,我从未解决过这个问题,因为在某些时候这部分代码与我的项目无关。无论如何,我祝你好运,如果你弄明白了,把它贴在这里,我很乐意接受它作为正确答案。
  • 经过大量搜索,我找到了这个完美的答案:stackoverflow.com/questions/33616927/…

标签: python class methods composition cython


【解决方案1】:

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

可能是您在这里使用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 是模块和类的名称。最后,从bendingForcesClass 类中创建一个ctypedef 怎么样?

【讨论】:

  • 由于编辑原始问题以使用 PEP8,此答案略有不同步;对此感到抱歉。
【解决方案2】:

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

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

对于您的示例,您需要一个文件 bendingForcesClass.pxd,它声明您要共享的类,以及所有 cimports、模块级变量、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 模块导入,使其成为有效的类型标识符,这应该可以解决您的问题。

【讨论】:

    【解决方案3】:

    您需要使用声明“.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: using imported class in a type declaration

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-21
      • 1970-01-01
      • 2023-03-16
      • 2017-01-16
      相关资源
      最近更新 更多