使用其他Cython代码中的自定义Cython代码
我目前正在尝试优化我的Python程序,并开始使用Cython,以减少函数调用的开销,也许以后还包括优化的C库函数.
I am currently trying to optimize my Python program and got started with Cython in order to reduce the function calling overhead and perhaps later on include optimized C-libraries functions.
所以我遇到了第一个问题:
So I ran into the first problem:
我在代码中使用组合来创建一个更大的类.到目前为止,我已经将我的Python类之一转换为Cython(这很困难).这是代码:
I am using composition in my code to create a larger class. So far I have gotten one of my Python classes converted to Cython (which was difficult enough). Here's the code:
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 my composed Python/Cython class I am calling the class-method calculate
, so that in my composed class I have the following (reduced) code:
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
的类型-根据文档(提早绑定).我已经尝试了以下方法,但不起作用:
I have found out that cpdef
makes the method/functions callable from Python and Cython, which is great and works, as long as I don't try to define the type of self.bendingForces
beforehand - which according to the documentation (Early Binding For Speed) is necessary in order to remove the function-calling overhead. I have tried the following, which does not work:
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
时,出现此错误:
With this I get this error, when trying to build membraneClass.pyx
with Cython:
membraneClass.pyx:18:6: 'bendingForcesClass' is not a type identifier
building 'membraneClass' extension
请注意,声明位于两个单独的文件中,这使此操作更加困难.
Note that the declarations are in two separate files, which makes this more difficult.
那么我该如何完成呢?如果有人能给我一个指针,我将非常感激,因为除了上面给出的链接之外,我找不到关于此的任何信息.
So I how do I get this done? I would be very thankful if someone could give me a pointer, as I can't find any information about this, besides the link given above.
感谢和问候!
免责声明:这个问题已经很久了,我不确定当前的解决方案是否适用于2011 Cython代码.
Disclaimer: This question is very old and I am not sure the current solution would work for 2011 Cython code.
为了从另一个文件导入扩展类(cdef类),您需要提供一个.pxd 文件(也称为定义文件),用于声明所有C类,属性和方法.请参阅文档中的共享扩展类型供参考.
In order to cimport an extension class (cdef class) from another file you need to provide a .pxd file (also known as a definitions file) declaring all C classes, attributes and methods. See Sharing Extension Types in the documentation for reference.
对于您的示例,您需要一个文件bendingForcesClass.pxd
,该文件声明要共享的类,以及所有cimport,模块级变量,typedef等:
For your example, you would need a file bendingForcesClass.pxd
, which declares the class you want to share, as well as all cimports, module level variables, typedefs, etc.:
# 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
现在可以(必须)从.pyx
文件中删除在.pxd
文件中声明的所有导入,变量和属性:
All imports, variables, and attributes that now are declared in the .pxd
file can (and have to be) removed from the .pyx
file:
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
现在可以从其他Cython模块中导入cdef类bendingForcesClass
,使其成为有效的类型标识符,这应该可以解决您的问题.
Now your cdef class bendingForcesClass
can be cimported from other Cython modules, making it a valid type identifier, which should solve your problem.