這是我的第一篇翻譯,希望大家多多給出意見和建議。
如有轉載,請注明出處。
原文來自:https://stackoverflow.com/questions/28362009/definition-of-def-cdef-and-cpdef-in-cython
問題
我想知道在我聲明一個函數時def
, cdef
, cpdef
的區別。
def
與其他兩種的區別還算大致清晰。可是有時我見到聲明時添加了返回值,有時見到的聲明卻沒有添加返回值。
我還想知道在cython
中如何聲明一個字符串變量,因為我不知道怎么搞,我就按照聲明對象的方式做了。
回答0
def
用來在Python中聲明一個函數。因為Cython是基於C runtime的,所以允許我們使用cpdef
。
cdef
在C語言層面聲明了函數。正如我們所知道的在C語言中你必須為每一個函數定義返回值的類型。有事函數返回值為 void
,這就等於Python中的 return
。
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
回答1
最關鍵的不同在於 where the function can be called from,def
函數可以被Python和Cython調用,cdef
函數可以被Cython和C調用。
這兩種類型的函數都是既可以被帶類型的變量也可以被不帶類型的變量被聲明,並且都會被Cython編譯為C。
# 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可見(一旦它被imported Cython module中。而 g
不可能被call from Python,它將被翻譯成C signature:
PyObject* some_name(int, struct __pyx_obj_11name_of_module_C *, PyObject*)
其中的 struct __pyx_obj_11name_of_module_C *
是我們的 class C 翻譯成的 C struct。這就允許我們把它傳遞給 C 函數,比如作為一個函數指針。
相對而言,f
就不能輕易的被C調用了。
cdef
函數的限制
cdef
函數不能在我們的函數內定義。這是因為沒有方法可以存儲獲取變量在C函數指針,如下代碼就是不允許的。
# WON'T WORK!
def g(a):
cdef (int b):
return a+b
cdef
函數不能處理 *args
*kwargs
類型的變量。這主要是因為它們不能輕易的翻譯成 C signature。
cdef
函數的優勢
cdef
函數可以接受任何類型的變量,包括哪些Python中沒有的類型,比如指針。
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
函數(使得我們可以從Pyhton調用)。就允許的變量類型而言,cpdef
函數具有 cdef
和 def
函數的限制。
什么時候使用 cdef
和 cpdef
函數?
一旦函數被調用,那么 cdef 和 def 函數內部代碼的運行速度沒有區別。
因此我們僅在以下條件下使用 cdef 函數:
- 需要傳遞非Python類型
- 需要傳遞它作為一個函數指針到C
- 需要經常調用(加速函數調用很重要)而且不需要從Python調用
使用 cpdef 函數的條件:
- 需要經常調用(所以使用加速函數調用很重要)而且需要從Python調用