[PYTHON] Da die Handhabung der Cython-Form mühsam war, fasste ich die Punkte zusammen, bei denen ich vorsichtig war

Es gibt eine Erklärung zur Verwendung von Cython, aber ich hatte das Gefühl, dass es nur wenige Artikel über Typen gibt, daher werde ich sie zusammenfassen. Cython ist eine Sprache, mit der Sie Schnittstellen zwischen C und Python in einem Schreibstil erstellen können, der fast dem von Python entspricht und der Python voraussichtlich beschleunigen wird. Typfehler treten jedoch häufig aufgrund der Mischung von C- und Python-Typen auf. Ich dachte, Cythons Schwierigkeit sei ** Typkontrolle **.

Fusion von statischer und dynamischer Typisierung

Cython ist eine Sprache, die dynamisch wie Python und statisch wie C typisiert werden kann. Es ist eine praktische Funktion, mit der Sie die Stärken der dynamischen und statischen Typisierung in Python nutzen können. In Cython sind jedoch viele Punkte zu beachten, da nicht nur Python-Typen, sondern auch C-Typen gemischt werden. Beachten Sie bei der Verwendung von Cython, dass ** Cython es als Python-Typ behandelt, sofern Sie es nicht explizit eingeben. (Wenn die Entität kein Typ auf Python-Ebene ist, wird sie in einen Typ auf C-Ebene umgewandelt.) **. Übrigens wird in Cython "vector " als "vector [int]" geschrieben.

    cdef vector[int] vec1 #C-Level-Typ

In Cython können Variablen mit cdef als C-Level-Typen deklariert werden. Beachten Sie, dass dieses cdef die Einschränkung hat, dass es am Anfang der Funktion geschrieben werden muss, mit Ausnahme von Kommentaren wie docstring. Mit anderen Worten, der Typ "cdef" kann nicht durch Verzweigen mit der "if-Anweisung" geändert werden, wie unten gezeigt.

#Ich kann so nicht schreiben
cdef func0(type):
    if type == "double":
        cdef double x = 10
        return x
    elif type == "int":
        cdef double y = 10
        return y

In Cython kann der Rückgabewert auch explizit angegeben werden. Diese Typspezifikation ist optional, wenn der Python-Typ der Rückgabewert ist, aber wenn der C-Level-Typ der Rückgabewert ist, muss der Typ angegeben werden. Wenn nicht angegeben, wird es in einen Python-Level-Typ konvertiert.

cdef func1(type):
     cdef vector[double] vec
     return vec #Jedes Element wird in eine Liste von Floats konvertiert

cdef vector[double] func2(type):#Geben Sie den Rückgabetyp an
     cdef vector[double] vec
     return vec #vector[double]Kehre zurück wie es ist

Cython kann implizit zwischen Python- und C-Level-Typen konvertieren. Beispielsweise konvertiert Cython automatisch "vector" in "list" und "double" in "float" für "vector ", ohne den Rückgabetyp vector [double] anzugeben.

Wenn der Typ, den Sie zurückgeben möchten, ein benutzerdefinierter Typ oder ein C-Bibliothek-spezifischer Typ ist, den Cython nicht verarbeiten kann, tritt ein Kompilierungsfehler auf, da die Konvertierung in die Python-Ebene nicht definiert ist. Im folgenden Beispiel wird der in C definierte Typ mit dem Namen MyClass aus der Funktion cdef zurückgegeben. Dieser MyClass-Typ definiert nicht, wie er in einen Python-Typ konvertiert werden soll. Daher tritt im folgenden Beispiel ein Fehler auf.

cdef func3():
    cdef MyClass x = MyClass()
    return x #Fehler Der MyClass-Typ kann nicht in den Python-Typ konvertiert werden

func3()

Wenn Sie einen Typwert auf C-Ebene zurückgeben möchten, müssen Sie den Rückgabetyp wie folgt angeben.

cdef MyClass func3():
    cdef MyClass x = MyClass()
    return x #OK Der Rückgabewert ist MyClass

func3()

Dies gilt auch für "Vektor", dessen Element MyClass ist.

Typ gegossen und überladen

Cython beschleunigt nicht nur Python, sondern hat auch den Reiz, C-Funktionen und -Typen umschließen zu können. Ich habe auch versucht, es zu verpacken, aber es war ziemlich umständlich, als ich eine Funktion umbrechen wollte, die in C überladen war.

cdef extern from "rect.h":
    int area(int x,int y)
    double area(double x,double y)

Angenommen, Sie haben eine Funktion wie die oben beschriebene. Ich möchte die Funktion so ändern, dass sie abhängig vom Typ von x aufgerufen wird. Schreiben Sie sie also wie folgt. Dann tritt ein Fehler auf.

#Fehler: Die entsprechende Methode kann nicht aufgerufen werden
def py_area (x,y):
   if type(x) == int:
        return area(x,y) 
   elif type(x) == float:
        return area(x,y) 

Wenn Sie es so schreiben möchten, müssen Sie alle zu übergebenden Werte explizit als tatsächliche Argumente an den entsprechenden Typ umwandeln, bevor Sie sie übergeben. Mit anderen Worten, die Typumwandlung wird für die explizite direkte Eingabe verwendet.

#OK
def py_area (x,y):
    if type(x) == int:
        return area(<int>x,<int>y) 
    elif type(x) == float:
        return area(<double>x,<double>y) 

Wenn das formale Argument jedoch durch Übergabe als Referenz deklariert wird, kann das formale Argument nicht übergeben werden, während es an Ort und Stelle gegossen wird. Zu diesem Zeitpunkt ist es möglich, durch Deklarieren des Typs mit "cdef" im Voraus zu übergeben, während der Typ explizit angegeben wird.

Zum Beispiel, wenn die Funktion wie folgt aussieht

cdef extern from "rect.h":
    int area(int& x,int& y)
    double area(double& x,double& y)

Es ist notwendig, den bisherigen Schreibstil auf den folgenden Schreibstil zu ändern.

def py_area (x,y):
    cdef:
        int x1
        int y1
        double x2
        double y2
    if type(x) == int:
       x1 = x
       y1 = y
       return area(x1,y1) 
    elif type(x) == float:
       x2 = x
       y2 = y
       return area(x2,y2) 

Selbst wenn das formale Argument im Referenztyp definiert ist, tritt kein Fehler auf.

Fused type Cython hat eine Funktion namens ** Fused Type **. Dies ist eine Funktion von Cython, die effektiv Vorlagentypen verwendet. Es kann verwendet werden, wenn es mehrere Arten von Rückgabewerten und Argumenten geben kann.

#Listen Sie einen beliebigen Typ auf
ctypedef fused my_type:
    hoge
    foo
    bar 

Durch Aufzählen der oben beschriebenen Typen von "Fused Type" wird "my_type" als "hoge", "foo" und "bar" behandelt. Auf diese Weise kann die Typkonvertierung zwischen C und Python einer mehrdimensionalen Liste wie folgt realisiert werden. "PyClass" ist der Typ "MyClass" in Python.

ctypedef fused T:
    MyClass
    vector[MyClass]

cdef vector_to_list (T x):
 if T == vector[MyClass]:
    return [vector_to_list(i) for i in range(<vector[MyClass]>x.size())]
 else :  
    return PyClass(x)

Der fusionierte Typ wird syntaktisch unter Berücksichtigung der Möglichkeit aller Typen analysiert. Im obigen Beispiel wird beispielsweise Cythons x sowohl als "MyClass" als auch als "Vektor [MyClass]" betrachtet. Wenn Sie wie folgt schreiben, ohne den Typ durch Casting explizit anzugeben, tritt ein Fehler auf, da MyClass nicht über "size ()" verfügt.

ctypedef fused T:
    MyClass
    vector[MyClass]

cdef vector_to_list (T x):
 if T == vector[MyClass]:
    return [vector_to_list(i) for i in range(x.size())] # (1)
 else :  
    return PyClass(x)

In diesem Beispiel wird die Zeile (1) nicht mit "<vector [MyClass]>" umgewandelt, daher wird davon ausgegangen, dass der Typ "T" MyClass sein kann. Und ich erhalte die Fehlermeldung, dass size () in MyClass nicht definiert ist.

Zusammenfassung

Da Cython eine Sprache ist, die C und Python kombiniert, kann es diese beiden Eigenschaften nutzen, aber ich fand es sehr schwierig. Wenn Sie Probleme mit der Eingabe von Cython haben, sollten Sie vorerst die statische Eingabe und das Casting mit cdef gut nutzen, um durchzukommen.

Verweise

Recommended Posts

Da die Handhabung der Cython-Form mühsam war, fasste ich die Punkte zusammen, bei denen ich vorsichtig war
Ich habe den Python-Datenanalysetest bestanden und die Punkte zusammengefasst