Определение 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.