Использование самоопределенного кода 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 я вызываю метод класса 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
Обратите внимание, что объявления находятся в двух отдельных файлах, что затрудняет это.
Итак, как мне это сделать? Я был бы очень благодарен, если бы кто-то мог дать мне указатель, поскольку я не могу найти никакой информации об этом, кроме ссылки, приведенной выше.
Спасибо и с наилучшими пожеланиями!
Ответы
Ответ 1
Отказ от ответственности: этот вопрос очень старый, и я не уверен, что текущее решение будет работать для кода Cython 2011 года.
Чтобы импортировать класс расширения (класс cdef) из другого файла, вам необходимо предоставить файл . pxd (также известный как определения файл), объявляющий все классы, атрибуты и методы C. См. Разделение типов расширений в документации для справки.
Для вашего примера вам понадобится файл bendingForcesClass.pxd
, который объявит класс, который вы хотите предоставить, а также все cimports, переменные уровня модуля, typedefs и т.д.:
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
может быть cimported из других модулей Cython, что делает его допустимым идентификатором типа, который должен решить вашу проблему.
Ответ 2
Вам нужно использовать файл декларации ".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: использование импортированного класса в объявлении типа
Ответ 3
Вероятно, это не источник ошибки, но для того, чтобы сузить проблему, вы можете попробовать следующее:
Может быть, вы используете 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
?