Il y a une explication sur la façon d'utiliser Cython, mais j'ai senti qu'il y avait peu d'articles sur les types, donc je vais le résumer. Cython est un langage qui vous permet de créer des interfaces entre C et Python dans un style d'écriture qui est presque le même que Python, et qui devrait accélérer Python. Cependant, un mélange de types C et Python provoque des erreurs de type fréquentes. Je pensais que la difficulté de Cython était le ** contrôle de type **.
Cython est un langage qui peut être typé dynamiquement comme Python et statiquement typé comme C. C'est une fonction pratique qui vous permet de profiter des atouts du typage dynamique et du typage statique en Python, mais il y a de nombreux points à prendre en compte en Cython car non seulement les types Python mais aussi les types C sont mélangés.
Gardez à l'esprit lorsque vous utilisez Cython ** Cython le traite comme un type Python à moins que vous ne le saisissiez explicitement. (Si l'entité n'est pas un type de niveau Python, elle sera convertie en type de niveau C) **.
D'ailleurs, en Cython, vector <int>
s'écrit vector [int]
.
cdef vector[int] vec1 #Type de niveau C
En Cython, les variables peuvent être déclarées en tant que types de niveau C en utilisant cdef
. Notez que ce cdef
a la restriction qu'il doit être écrit au début de la fonction, sauf pour les commentaires tels que docstring. En d'autres termes, le type en «cdef» ne peut pas être changé en branchant dans «l'instruction if» comme indiqué ci-dessous.
#Je ne peux pas écrire comme ça
cdef func0(type):
if type == "double":
cdef double x = 10
return x
elif type == "int":
cdef double y = 10
return y
En Cython, la valeur de retour peut également être spécifiée explicitement. Cette spécification de type est facultative lorsque le type Python est la valeur de retour, mais lorsque le type de niveau C est la valeur de retour, le type doit être spécifié. S'il n'est pas spécifié, il sera converti en un type de niveau Python.
cdef func1(type):
cdef vector[double] vec
return vec #Chaque élément est converti en une liste de flottants
cdef vector[double] func2(type):#Spécifiez le type de retour
cdef vector[double] vec
return vec #vector[double]Revenir tel quel
Cython a la capacité de convertir implicitement entre les types au niveau Python et au niveau C. Par exemple, Cython convertit automatiquement «vector» en «liste» et «double» en «float» pour «vector
Si le type que vous souhaitez renvoyer est un type défini par l'utilisateur ou un type spécifique à la bibliothèque C que Cython ne peut pas gérer, une erreur de compilation se produira car la conversion au niveau Python n'est pas définie.
Dans l'exemple suivant, le type défini en C appelé MyClass est renvoyé depuis la fonction cdef
. Ce type MyClass ne définit pas comment le convertir en type Python, une erreur se produira donc dans l'exemple suivant.
cdef func3():
cdef MyClass x = MyClass()
return x #Le type d'erreur MyClass ne peut pas être converti en type Python
func3()
Par conséquent, si vous souhaitez renvoyer une valeur de type de niveau C, vous devez spécifier le type de retour comme suit.
cdef MyClass func3():
cdef MyClass x = MyClass()
return x #OK La valeur de retour est MyClass
func3()
Ceci s'applique également au «vecteur» dont l'élément est MyClass.
Cython accélère non seulement Python, mais il a également l'avantage de pouvoir encapsuler des fonctions et des types C. J'ai aussi essayé de l'envelopper, mais c'était assez gênant quand je voulais envelopper une fonction surchargée en C.
cdef extern from "rect.h":
int area(int x,int y)
double area(double x,double y)
Par exemple, supposons que vous ayez une fonction comme celle ci-dessus. Je veux changer la fonction pour appeler cela en fonction du type de x, alors écrivez-le comme suit. Ensuite, une erreur se produit.
#Erreur: impossible d'appeler la méthode appropriée
def py_area (x,y):
if type(x) == int:
return area(x,y)
elif type(x) == float:
return area(x,y)
Si vous voulez l'écrire comme ceci, vous devez convertir explicitement toutes les valeurs à passer en arguments réels dans le type approprié avant de les transmettre. En d'autres termes, le type cast est utilisé pour la saisie explicite à la volée.
#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)
Cependant, lorsque l'argument formel est déclaré en passant par référence, l'argument formel ne peut pas être passé tout en étant casté sur place. A ce moment, en déclarant le type avec cdef
à l'avance, il est possible de passer en spécifiant explicitement le type.
Par exemple, si la fonction ressemble à ci-dessous
cdef extern from "rect.h":
int area(int& x,int& y)
double area(double& x,double& y)
Il est nécessaire de changer le style d'écriture jusqu'à présent pour le style d'écriture suivant.
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)
Ensuite, même si l'argument formel est défini dans le type référence, aucune erreur ne se produit.
Fused type Cython a une fonction appelée ** Type fusionné **. Il s'agit d'une fonctionnalité de Cython qui utilise efficacement les types de modèles. Il peut être utilisé lorsqu'il peut y avoir plusieurs types de valeurs de retour et d'arguments.
#Liste de tout type
ctypedef fused my_type:
hoge
foo
bar
En énumérant les types de «type fusionné» comme décrit ci-dessus, «my_type» sera traité comme l'un des «hoge», «foo» et «bar».
En utilisant cela, la conversion de type entre C et Python d'une liste multidimensionnelle peut être réalisée comme suit. PyClass
est le type de MyClass
sur 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)
Le type fusionné est analysé syntaxiquement en considérant la possibilité de tous les types. Par exemple, dans l'exemple ci-dessus, le x de Cython est considéré non seulement comme «vector [MyClass]» mais aussi «MyClass». Si vous écrivez comme ci-dessous sans spécifier explicitement le type par conversion, une erreur se produira car MyClass n'a pas size ()
.
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)
Dans cet exemple, la ligne (1) n'est pas castée avec <vector [MyClass]>
, donc on considère que le type T
peut être MyClass. Et j'obtiens une erreur indiquant que size () n'est pas défini dans MyClass.
Puisque Cython est un langage qui combine C et Python, il peut tirer parti de ces deux caractéristiques, mais je l'ai trouvé beaucoup de problèmes.
Pour le moment, si vous rencontrez des problèmes avec le typage de Cython, faites bon usage du typage statique et du cast avec cdef
.
--Kurt W. Smith, traduit par Hideki Nakata, traduit par Takahiro Nagao, "Cython - Accélérer Python en fusionnant avec C" 2015