Использование самоопределенного кода Cython из другого кода Cython - PullRequest
11 голосов
/ 16 марта 2011

В настоящее время я пытаюсь оптимизировать свою программу на 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 заранее - что в соответствии с документация (Раннее связывание для скорости) необходима для устранения накладных расходов на вызов функции. Я пробовал следующее, которое не работает:

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

Обратите внимание, что объявления находятся в двух отдельных файлах, что делает это более трудным.

Итак, как мне это сделать? Я был бы очень благодарен, если бы кто-то мог дать мне указатель, поскольку я не могу найти никакой информации об этом, кроме ссылки, приведенной выше.

Спасибо и всего наилучшего!

Ответы [ 3 ]

6 голосов
/ 26 мая 2017

Отказ от ответственности: Этот вопрос очень старый, и я не уверен, что текущее решение будет работать для кода Cython 2011 года.

Чтобы импортировать класс расширения (класс cdef) из другого файла, вам необходимо предоставить файл .pxd (также известный как файл определений), объявляющий все классы, атрибуты и методы языка Си. См. Совместное использование типов расширений в документации для справки.

Для вашего примера вам понадобится файл 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 может быть импортирован из других модулей Cython, что делает его допустимым идентификатором типа, который должен решить вашу проблему.

4 голосов
/ 26 мая 2017

Вам нужно использовать файл декларации ".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: использование импортированного класса в объявлении типа

2 голосов
/ 18 марта 2011

Это, вероятно, не источник ошибки, а просто для того, чтобы сузить проблему, вы можете попробовать изменить следующее:

Может быть, вы используете 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?

...