简单而高级的答案是,NumPy 在 Python 的类型系统之上添加了第二个类型系统。
当您请求 NumPy 对象的 type 时,您会得到 容器 的类型——类似于 numpy.ndarray。但是当你请求dtype 时,你会得到elements 的(numpy-managed)类型。
>>> from numpy import *
>>> arr = array([1.0, 4.0, 3.14])
>>> type(arr)
<type 'numpy.ndarray'>
>>> arr.dtype
dtype('float64')
有时,当使用默认的 float 类型时,元素数据类型 (dtype) 等效于 Python 类型。但这是等价的,不完全相同:
>>> arr.dtype == float
True
>>> arr.dtype is float
False
在其他情况下,没有等效的 Python 类型。例如,当您指定 uint8 时。此类数据值/类型可以由 Python 管理,但与 C、Rust 和其他“系统语言”不同,管理直接与机器数据类型对齐的值(如 uint8 与“无符号字节”计算紧密对齐)不是Python 的常见用例。
因此,重要的是 NumPy 提供了像数组和矩阵这样的容器,它们在自己的类型系统下运行。它提供了一堆非常有用、优化良好的例程来操作这些容器(及其元素)。如果你小心的话,你可以混合搭配 NumPy 和普通的 Python 计算。
没有 Python 类型 uint8。有一个名为 uint8 的构造函数,调用时返回一个 NumPy 类型:
>>> u = uint8(44)
>>> u
44
>>> u.dtype
dtype('uint8')
>>> type(u)
<type 'numpy.uint8'>
那么“我可以创建一个类型为(不是 dtype)uint8 的数组吗...?”不,你不能。没有这样的动物。
你可以
在不使用 NumPy arrays(又名 NumPy 标量值)的情况下进行受限于 uint8 规则的计算。例如:
>>> uint8(44 + 1000)
20
>>> uint8(44) + uint8(1000)
20
但是如果你想计算 mod 256 的值,使用 Python 的 mod 运算符可能更容易:
>> (44 + 1000) % 256
20
将大于 255 的数据值驱动为 uint8 数据类型,然后进行算术运算是获得 mod-256 算术的一种相当后门的方法。如果您不小心,您将导致 Python 将您的值“升级”为完整整数(杀死您的 mod-256 方案),或触发溢出异常(因为在 C 和机器语言中运行良好的技巧通常被标记为高级语言)。