web-dev-qa-db-ja.com

cythonでのdef、cdef、cpdefの定義

関数を宣言するときに、defcdef、およびcpdefの違いを知りたいのですが。 defと他の人との違いは多かれ少なかれ明らかです。また、宣言に戻り値の型が追加されることもあります(cdef void/double/int... name)そして時々そうではない。

また、cythonで文字列変数を宣言する方法も知りたいのですが、知らなかったので、オブジェクトとして宣言しました。

19
Pablo

defはPythonで関数を宣言します。 CythonはCランタイムに基づいているため、cdefcpdefを使用できます。

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

要約すると、なぜdefcdefおよびcpdefを使用する必要があるのですか? Cythonを使用する場合、Pythonコードはコンパイル前にCコードに変換されるため、これにより、結果のCコードリストを制御できます。

詳細については、公式ドキュメントを読むことをお勧めします: http://docs.cython.org/src/reference/language_basics.html

5

主な違いは、関数をどこから呼び出すことができるかです。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(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オブジェクト、CではPyObject*)を返します。def関数は常にPythonオブジェクトを返すため、戻り値の型を指定することはできません。

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

cdef関数は、単純なC関数呼び出しに変換されるため、def関数よりもすばやく呼び出すことができます。

cpdef関数

cpdef関数により、Cythonはcdef関数(Cythonからの迅速な関数呼び出しを可能にする)とdef関数(Pythonからの呼び出しを可能にする)を生成します。内部的には、def関数はcdef関数を呼び出すだけです。許可される引数のタイプに関して、cpdef関数にはcdef関数とdef関数の両方のすべての制限があります。

cdef関数を使用する場合

関数が呼び出されると、cdef関数とdef関数内のコードが実行される速度に違いはありません。したがって、次の場合にのみcdef関数を使用してください。

  • Python以外のタイプを出し入れする必要があります。
  • 関数ポインタとしてCに渡す必要があります。
  • あなたはそれを頻繁に呼び出しており(したがって、高速化された関数呼び出しが重要です)、Pythonから呼び出す必要はありません。

頻繁に呼び出す場合はcpdef関数を使用しますが(したがって、高速化された関数呼び出しが重要です)、Pythonから呼び出す必要があります。

22
DavidW