我在cython中对这么多int
数据类型有点挣扎。
np.int, np.int_, np.int_t, int
我想int
在纯python中相当于np.int_
,那么np.int
从何而来?我找不到来自 numpy 的文档?另外,既然我们已经有了int
,为什么np.int_
存在?
在cython中,我想当用作cdef int
或ndarray[int]
时,int
变成C类型,当用作int()
时,它仍然是python caster?
np.int_
等同于C中的long
吗?那么cdef long
与cdef np.int_
相同?
在什么情况下我应该使用np.int_t
而不是np.int
?例如cdef np.int_t
,ndarray[np.int_t]
...
有人可以简要解释一下这些类型的错误使用将如何影响编译的cython代码的性能吗?
这有点复杂,因为名称根据上下文具有不同的含义。
int
-
在蟒蛇中
int
通常只是一个Python类型,它具有任意精度,这意味着您可以在其中存储任何可以想象的整数(只要您有足够的内存)。>>> int(10**50) 100000000000000000000000000000000000000000000000000
-
但是,当您将其用作 NumPy 数组的
dtype
时,它将被解释为np.int_
1。这不是任意精度,它将具有与 Clong
相同的大小:>>> np.array(10**50, dtype=int) OverflowError: Python int too large to convert to C long
这也意味着以下两个是等效的:
np.array([1,2,3], dtype=int) np.array([1,2,3], dtype=np.int_)
-
作为 Cython 类型标识符 它有另一种含义,这里它代表 c 类型
int
.它的精度有限(通常为 32 位)。您可以将其用作 Cython 类型,例如在使用cdef
定义变量时:cdef int value = 100 # variable cdef int[:] arr = ... # memoryview
作为
cdef
或cpdef
函数的返回值或参数值:cdef int my_function(int argument1, int argument2): # ...
作为
ndarray
的"通用":cimport numpy as cnp cdef cnp.ndarray[int, ndim=1] val = ...
对于类型转换:
avalue = <int>(another_value)
可能还有更多。
-
在Cython中,但作为Python类型。您仍然可以调用
int
,您将获得一个"Python int"(任意精度),或者将其用于isinstance
或用作np.array
的dtype
参数。这里的上下文很重要,因此转换为 Pythonint
与转换为 C int 不同:cdef object val = int(10) # Python int cdef int val = <int>(10) # C int
np.int
实际上这很容易。它只是int
的别名:
>>> int is np.int
True
因此,上面的一切都适用于np.int
。但是,您不能将其用作类型标识符,除非您在cimport
ed 包上使用它。在这种情况下,它表示 Python 整数类型。
cimport numpy as cnp
cpdef func(cnp.int obj):
return obj
这将期望obj
是 Python 整数而不是 NumPy 类型:
>>> func(np.int_(10))
TypeError: Argument 'obj' has incorrect type (expected int, got numpy.int32)
>>> func(10)
10
我对np.int
的建议:尽可能避免它。在Python代码中,它等同于int
,在Cython代码中,它也等同于Pythonint
但如果用作类型标识符,它可能会使您和每个阅读代码的人感到困惑!这当然让我感到困惑...
np.int_
实际上它只有一个含义:它是一个表示标量 NumPy 类型的Python 类型。你像 Python 一样使用它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
或者你用它来指定dtype
,例如用np.array
:
>>> np.array([1,2,3], dtype=np.int_)
array([1, 2, 3])
但是您不能将其用作 Cython 中的类型标识符。
cnp.int_t
这是np.int_
的类型标识符版本。这意味着您不能将其用作 dtype 参数。但是您可以将其用作cdef
声明的类型:
cimport numpy as cnp
import numpy as np
cdef cnp.int_t[:] arr = np.array([1,2,3], dtype=np.int_)
|---TYPE---| |---DTYPE---|
此示例(希望)表明带有尾随_t
的类型标识符实际上表示使用dtype而不带尾随t
的数组的类型。你不能在Cython代码中互换它们!
笔记
NumPy中还有几种数字类型,我将包含一个包含 NumPy dtype 和 Cython 类型标识符的列表,以及 C 类型标识符,这些标识符也可以在此处用于 Cython。但它基本上取自 NumPy 文档和 Cython NumPypxd
文件:
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
实际上有用于np.bool_
的Cython类型:cnp.npy_bool
和bint
但它们目前都不能用于NumPy数组。对于标量cnp.npy_bool
将只是一个无符号整数,而bint
将是一个布尔值。不知道那里发生了什么...
1摘自 NumPy 文档"数据类型对象">
内置的 Python 类型
当用于生成 dtype 对象时,几种 python 类型等效于相应的数组标量:
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_
是默认整数类型(如 NumPy 文档中所定义),但在 64 位系统上,这将是一个C long
。np.intc
是默认C int
int32
或int64
。np.int
是内置int
函数的别名
>>> np.int(2.4)
2
>>> np.int is int # object id equality
True
cython 数据类型应反映C
数据类型,因此cdef int a
是一个C int
,依此类推。
至于np.int_t
,这是 NumPynp.int_
数据类型的Cython
编译时等效值,np.int64_t
Cython
编译时等效于np.int64
这是对Cython代码中int
和np.int_t
之间区别的澄清,它们并不相同:
np.int_t
映射到 Cython 代码中的long
而不是int
。
这意味着:
- 在 64 位 Windows(即使用 MSVC 编译)上,
int
是 4 个字节,但也long
(因此np.int_t
)。 - 在 64 位 Linux(即使用 gcc 编译)上,
int
是 4 个字节,但long
(因此np.int_t
)是 8 个字节!
np.int
-numpy-array 将映射到 Cython 中的np.int_t[:]
内存视图,这是正确的,因为以下代码:
import numpy as np
a = np.zeros(1, np.int_) # or np.zeros(1, np.int)
print(a.itemsize)
将在Windows上产生4
(Windows上以字节为单位的long
大小),在Linux上产生8
。
通常,准确指定值的大小是有意义的,例如,通过使用np.int32
和np.int64
,它们将映射到Cython中的np.int32_t
和np.int64_t
,并且在所有平台上具有相同的大小。