cython中np.int,np.int_,int和np.int_t之间的区别?

col*_*ang 29 c python numpy cython

int对cython中的这么多数据类型感到有点挣扎.

np.int, np.int_, np.int_t, int

我猜int在纯python中相当于np.int_,那么它np.int来自哪里呢?我从numpy找不到文件?另外,np.int_鉴于我们已经存在,为什么存在int

在cython中,我猜想int当它被用作cdef int或者成为C型时ndarray[int],并且当int()它被用作python施法者时它会被使用?

np.int_相当于long用C?那cdef long是相同的cdef np.int_吗?

我应该在什么情况下使用np.int_t而不是np.int?例如cdef np.int_t,ndarray[np.int_t]......

有人可以简单解释这些类型的错误使用会如何影响已编译的cython代码的性能?

MSe*_*ert 30

它有点复杂,因为根据上下文,名称具有不同的含义.

int

  1. 在Python中

    int通常仅仅是一个Python类型,它是任意精度的,这意味着你可以存储在它里面的任何可能的整数(只要你有足够的内存).

    >>> int(10**50)
    100000000000000000000000000000000000000000000000000
    
    Run Code Online (Sandbox Code Playgroud)
  2. 但是,当您将它用作dtypeNumPy数组时,它将被解释为np.int_ 1.这不是任意精度,它将与C的大小相同long:

    >>> np.array(10**50, dtype=int)
    OverflowError: Python int too large to convert to C long
    
    Run Code Online (Sandbox Code Playgroud)

    这也意味着以下两个是等价的:

    np.array([1,2,3], dtype=int)
    np.array([1,2,3], dtype=np.int_)
    
    Run Code Online (Sandbox Code Playgroud)
  3. 作为Cython类型标识符,它具有另一种含义,这里它代表类型int.它的精度有限(通常为32位).您可以将它用作Cython类型,例如在使用以下内容定义变量时cdef:

    cdef int value = 100    # variable
    cdef int[:] arr = ...   # memoryview
    
    Run Code Online (Sandbox Code Playgroud)

    作为返回值或参数值cdefcpdef功能:

    cdef int my_function(int argument1, int argument2):
        # ...
    
    Run Code Online (Sandbox Code Playgroud)

    作为"通用" ndarray:

    cimport numpy as cnp
    cdef cnp.ndarray[int, ndim=1] val = ...
    
    Run Code Online (Sandbox Code Playgroud)

    用于铸造:

    avalue = <int>(another_value)
    
    Run Code Online (Sandbox Code Playgroud)

    可能还有更多.

  4. 在Cython中,但作为Python类型.你仍然可以调用int,你将得到一个"Python int"(任意精度),或者用它isinstance作为dtype参数np.array.这里的上下文很重要,因此转换为Python int与转换为C int不同:

    cdef object val = int(10)  # Python int
    cdef int val = <int>(10)   # C int
    
    Run Code Online (Sandbox Code Playgroud)

np.int

其实这很容易.它只是一个别名int:

>>> int is np.int
True
Run Code Online (Sandbox Code Playgroud)

因此,上述所有内容也适用np.int于此.但是,除非在cimported包上使用它,否则不能将其用作类型标识符.在这种情况下,它表示Python整数类型.

cimport numpy as cnp

cpdef func(cnp.int obj):
    return obj
Run Code Online (Sandbox Code Playgroud)

这将obj是一个Python整数而不是NumPy类型:

>>> func(np.int_(10))
TypeError: Argument 'obj' has incorrect type (expected int, got numpy.int32)
>>> func(10)
10
Run Code Online (Sandbox Code Playgroud)

我的建议np.int:尽可能避免使用它.在Python代码中,它等同于int和在Cython代码中它也等同于Pythons int但如果用作类型标识符,它可能会让你和每个读取代码的人感到困惑!这当然让我很困惑......

np.int_

实际上它只有一个含义:它是一种代表标量NumPy类型的Python类型.你像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
Run Code Online (Sandbox Code Playgroud)

或者您使用它来指定dtype,例如np.array:

>>> np.array([1,2,3], dtype=np.int_)
array([1, 2, 3])
Run Code Online (Sandbox Code Playgroud)

但是你不能在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---|
Run Code Online (Sandbox Code Playgroud)

这个例子(希望如此)表明带有尾部的类型标识符_t实际上表示使用没有尾部的dtype的数组类型t.你不能在Cython代码中交换它们!

笔记

在NumPy中还有几种数字类型我将包含一个包含NumPy dtype和Cython类型标识符的列表以及也可以在Cython中使用的C类型标识符.但它基本上取自NumPy文档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
Run Code Online (Sandbox Code Playgroud)

其实还有用Cython类型np.bool_:cnp.npy_boolbint,但他们都不能用于当前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_
Run Code Online (Sandbox Code Playgroud)

  • 非常感谢这篇非常详尽的概述! (2认同)

Mat*_*yra 7

np.int_是默认的整数类型(在NumPy文档中定义),在64位系统上,这将是一个C long.np.intc是默认的C int或者int32int64.np.int是内置int函数的别名

>>> np.int(2.4)
2
>>> np.int is int  # object id equality
True
Run Code Online (Sandbox Code Playgroud)

cython数据类型应该反映C数据类型,因此cdef int aC int等等.

至于np.int_t那是Cython编译时当量NumPy的的np.int_数据类型,np.int64_t是在Cython编译时的等效np.int64