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

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

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

2 ответа

Решение

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

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

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

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

Основное различие заключается в том, откуда функция может быть вызвана: 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* в с). 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.

Другие вопросы по тегам