J'ai un peu de mal avec tant de types de données int
dans cython.
np.int, np.int_, np.int_t, int
Je suppose que int
en pur python est équivalent à np.int_
, Alors d'où vient np.int
? Je ne trouve pas le document de numpy? Aussi, pourquoi np.int_
Existe-t-il alors que nous avons déjà int
?
Dans cython, je suppose que int
devient un type C lorsqu'il est utilisé comme cdef int
Ou ndarray[int]
, Et lorsqu'il est utilisé comme int()
il reste le python roulette?
np.int_
Est-il équivalent à long
en C? donc cdef long
est identique à cdef np.int_
?
Dans quelles circonstances dois-je utiliser np.int_t
Au lieu de np.int
? par exemple. cdef np.int_t
, ndarray[np.int_t]
...
Quelqu'un peut-il expliquer brièvement comment une mauvaise utilisation de ces types affecterait les performances du code cython compilé?
C'est un peu compliqué car les noms ont des significations différentes selon le contexte.
int
En Python
Le int
est normalement juste un Python, il est d'une précision arbitraire, ce qui signifie que vous pouvez stocker n'importe quel entier imaginable à l'intérieur (tant que vous avez suffisamment de mémoire).
>>> int(10**50)
100000000000000000000000000000000000000000000000000
Cependant, lorsque vous l'utilisez comme dtype
pour un tableau NumPy, il sera interprété comme np.int_
1. Ce qui n'est pas pas de précision arbitraire, il aura la même taille que C long
:
>>> np.array(10**50, dtype=int)
OverflowError: Python int too large to convert to C long
Cela signifie également que les deux suivants sont équivalents:
np.array([1,2,3], dtype=int)
np.array([1,2,3], dtype=np.int_)
En tant qu'identifiant de type Cython, il a une autre signification, ici il représente le type cint
. Il est d'une précision limitée (généralement 32 bits). Vous pouvez l'utiliser comme type Cython, par exemple lors de la définition de variables avec cdef
:
cdef int value = 100 # variable
cdef int[:] arr = ... # memoryview
Comme valeur de retour ou valeur d'argument pour les fonctions cdef
ou cpdef
:
cdef int my_function(int argument1, int argument2):
# ...
En tant que "générique" pour ndarray
:
cimport numpy as cnp
cdef cnp.ndarray[int, ndim=1] val = ...
Pour le moulage de type:
avalue = <int>(another_value)
Et probablement beaucoup plus.
En Cython mais comme Python. Vous pouvez toujours appeler int
et vous obtiendrez un "Python int" (de précision arbitraire), ou utilisez-le pour isinstance
ou comme argument dtype
pour np.array
. Ici, le contexte est important, donc la conversion en a Python int
est différente de la conversion en un C int:
cdef object val = int(10) # Python int
cdef int val = <int>(10) # C int
np.int
En fait, c'est très simple. C'est juste un alias pour int
:
>>> int is np.int
True
Donc, tout ce qui précède s'applique également à np.int
. Cependant, vous ne pouvez pas l'utiliser comme identificateur de type, sauf lorsque vous l'utilisez sur le package ed cimport
. Dans ce cas, il représente le type entier Python.
cimport numpy as cnp
cpdef func(cnp.int obj):
return obj
Cela supposera que obj
sera un Python entier pas un type NumPy :
>>> func(np.int_(10))
TypeError: Argument 'obj' has incorrect type (expected int, got numpy.int32)
>>> func(10)
10
Mon conseil concernant np.int
: Évitez-le autant que possible. Dans Python c'est équivalent à int
et dans le code Cython c'est aussi équivalent à Pythons int
mais s'il est utilisé comme identificateur de type, cela vous confondra probablement, vous et tout le monde qui lit le code! Cela m'a certainement dérouté ...
np.int_
En fait, il n'a qu'une seule signification: c'est un type Python qui représente un type NumPy scalaire. Vous l'utilisez comme Pythons int
:
>>> np.int_(10) # looks like a normal Python integer
10
>>> type(np.int_(10)) # but isn't (output may vary depending on your system!)
numpy.int32
Ou vous l'utilisez pour spécifier le dtype
, par exemple avec np.array
:
>>> np.array([1,2,3], dtype=np.int_)
array([1, 2, 3])
Mais vous ne pouvez pas l'utiliser comme identificateur de type en Cython.
cnp.int_t
Il s'agit de la version de l'identificateur de type pour np.int_
. Cela signifie que vous ne pouvez pas l'utiliser comme argument dtype. Mais vous pouvez l'utiliser comme type pour les déclarations cdef
:
cimport numpy as cnp
import numpy as np
cdef cnp.int_t[:] arr = np.array([1,2,3], dtype=np.int_)
|---TYPE---| |---DTYPE---|
Cet exemple (espérons-le) montre que l'identificateur de type avec le _t
De fin représente en fait le type d'un tableau utilisant le dtype sans le à la fin t
. Vous ne pouvez pas les échanger en code Cython!
Il existe plusieurs autres types numériques dans NumPy. Je vais inclure une liste contenant le dtype NumPy et l'identificateur de type Cython et l'identifiant de type C qui pourraient également être utilisés en Cython ici. Mais il est essentiellement tiré de la documentation NumPy et du fichier Cython NumPy pxd
:
NumPy dtype Numpy Cython type C Cython type identifier
np.bool_ None None
np.int_ cnp.int_t long
np.intc None int
np.intp cnp.intp_t ssize_t
np.int8 cnp.int8_t signed char
np.int16 cnp.int16_t signed short
np.int32 cnp.int32_t signed int
np.int64 cnp.int64_t signed long long
np.uint8 cnp.uint8_t unsigned char
np.uint16 cnp.uint16_t unsigned short
np.uint32 cnp.uint32_t unsigned int
np.uint64 cnp.uint64_t unsigned long
np.float_ cnp.float64_t double
np.float32 cnp.float32_t float
np.float64 cnp.float64_t double
np.complex_ cnp.complex128_t double complex
np.complex64 cnp.complex64_t float complex
np.complex128 cnp.complex128_t double complex
En fait, il existe des types Cython pour np.bool_
: cnp.npy_bool
Et bint
mais les deux ne peuvent pas être utilisés pour les tableaux NumPy actuellement. Pour les scalaires, cnp.npy_bool
Sera simplement un entier non signé tandis que bint
sera un booléen. Je ne sais pas ce qui se passe là-bas ...
1 Tiré de la documentation NumPy "Objets de type de données"
Intégré Python
Plusieurs types python sont équivalents à un scalaire de tableau correspondant lorsqu'ils sont utilisés pour générer un objet dtype:
int np.int_ bool np.bool_ float np.float_ complex np.cfloat bytes np.bytes_ str np.bytes_ (Python2) or np.unicode_ (Python3) unicode np.unicode_ buffer np.void (all others) np.object_
np.int_
est le type d'entier par défaut ( tel que défini dans les documents NumPy ), sur un système 64 bits, ce serait un C long
. np.intc
est la valeur par défaut C int
Soit int32
ou int64
. np.int
est un alias de la fonction intégrée int
>>> np.int(2.4)
2
>>> np.int is int # object id equality
True
Les types de données cython doivent refléter les types de données C
, donc cdef int a
est un C int
etc.
Pour ce qui est de np.int_t
c'est l'équivalent de temps de compilation Cython
de NumPy np.int_
Type de données, np.int64_t
est l'équivalent en temps de compilation de Cython
de np.int64