Определение def, cdef и cpdef в cython

Я хотел бы узнать разницу между def, cdef и cpdef, когда я объявляю функцию. Разница между def и другими более или менее ясна. И я также видел, что иногда он добавлял возвращаемый тип в декларации (cdef void/double/int... name), а иногда и нет.

Я также хотел бы знать, как объявить строчную переменную в cython, так как я этого не знал, я объявил ее как объект.

Ответ 1

def объявляет функцию в Python. Поскольку Cython основан на времени выполнения C, он позволяет использовать cdef и cpdef.

cdef объявляет функцию в слое языка C. Как вы знаете (или нет?) На языке C вы должны определить тип возвращаемого значения для каждой функции. Иногда функция возвращает с void, и она равна только для return в Python.

Python - это объектно-ориентированный язык. Таким образом, вы также можете определить метод класса в слое языка С++ и переопределить эти методы в подклассах:

cdef class A:
    cdef foo(self):
        print "A"

cdef class B(A)
    cdef foo(self, x=None)
        print "B", x

cdef class C(B):
    cpdef foo(self, x=True, int k=3)
        print "C", x, k

Резюме, зачем нам использовать def, cdef и cpdef? Потому что, если вы используете Cython, ваш код Python будет преобразован в код C перед компиляцией. Таким образом, вы можете контролировать список C-кодов.

Для получения дополнительной информации я предлагаю вам ознакомиться с официальной документацией: http://docs.cython.org/src/reference/language_basics.html

Ответ 2

Основное различие заключается в том, где функция может быть вызвана: def функции могут быть вызваны из Python и Cython, а функция cdef может быть вызвана из Cython и C.

Оба типа функций могут быть объявлены с помощью любой комбинации типизированных и нетипизированных аргументов, и в обоих случаях внутренности скомпилированы в C по Cython (и скомпилированный код должен быть очень и очень похожим):

# A Cython class for illustrative purposes
cdef class C:
   pass

def f(int arg1, C arg2, arg3):
    # takes an integer, a "C" and an untyped generic python object
    pass

cdef g(int arg1, C arg2, arg3):
    pass

В приведенном выше примере f будет виден Python (после импорта модуля Cython), а g не будет и не может быть вызван из Python. g преобразуется в C-подпись:

PyObject* some_name(int, struct __pyx_obj_11name_of_module_C *, PyObject*)

(где struct __pyx_obj_11name_of_module_C * - это только C-структура, в которую переводится наш класс C). Это позволяет, например, передавать функции C в качестве указателя функции. Напротив, f нельзя (легко) вызвать из C.

Ограничения функций cdef:

cdef функции не могут быть определены внутри других функций - это связано с тем, что нет никакого способа хранения каких-либо захваченных переменных в указателе функции C. Например. следующий код является незаконным:

# WON'T WORK!
def g(a):
   cdef (int b):
      return a+b

cdef функции не могут принимать аргументы типа *args и **kwargs. Это потому, что они не могут быть легко переведены на C-подпись.

Преимущества функций cdef

cdef функции могут принимать любые типы аргументов, в том числе те, которые не имеют эквивалента Python (например, указатели). def функции не могут быть такими, поскольку они должны быть вызваны из Python.

cdef функции также могут указывать тип возврата (если он не указан, они возвращают объект Python, PyObject* в C). def функции всегда возвращают объект Python, поэтому не могут указывать тип возвращаемого значения:

cdef int h(int* a):
    # specify a return type and take a non-Python compatible argument
    return a[0]

cdef функции быстрее вызывать, чем функции def, потому что они переводят на простой вызов функции C.

cpdef функции

cpdef функции заставляют Cython генерировать функцию cdef (которая позволяет быстро вызвать функцию из Cython) и функцию def (что позволяет вам вызывать ее из Python). В интерактивном режиме функция def просто вызывает функцию cdef. В терминах допустимых типов аргументов функции cpdef имеют все ограничения как функций cdef, так и def.

Когда использовать функцию cdef

Как только функция была вызвана, нет разницы в скорости, с которой работает код внутри функции cdef и def. Поэтому используйте функцию cdef, если:

  • Вам нужно передать не-типы Python в или из, или
  • Вам нужно передать его на C как указатель функции или
  • Вы часто вызываете его (так что вызов функции расширенной функции важен), и вам не нужно вызывать его из Python.

Используйте функцию cpdef, когда вы ее часто вызываете (так что вызов функции ускоренного вызова важен), но вам нужно вызвать его из Python.