NumPy 2.x 完全指南【二十二】数组标量
文章目录
- 1. 标量(Scalar )
- 2. 数组标量(Array Scalar)
- 3. 标量类型
- 3.1 基类
- 3.1.1 generic
- 3.1.2 number
- 3.1.3 flexible
- 3.2 整数类型
- 3.2.1 有符号整数
- 3.2.2 无符号整数
- 3.3 不精确类型
- 3.3.1 浮点数
- 3.3.2 复数
- 3.4 其他类型
- 3.4.1 布尔类型
- 3.4.2 日期时间与时间差
- 3.4.3 对象类型
- 3.4.4 灵活类型(无预定义长度)
- 4. 对象属性
- 5. 对象方法
- 6. 索引
1. 标量(Scalar )
Scalar [ˈskeɪlər]
作为名词时翻译为数量、标量。
定义:只有大小,没有方向的量。
在数学中,一般称为数量,当我们还在蹒跚学步、咿咿呀呀的时候,其实就已经开始学习最简单的标量,例如数字 1
、2
、3
。在初中物理中,我们也学过很多标量类型的物理量,比如质量、密度、温度等等。
标量在计算时遵循一般的代数运算法则,这些肯定也是大家最熟悉的了,比如小学的加法、减法、乘法、除法四则运算,初中学过的指数运算、比较运算、绝对值、根运算、对数运算以及模运算等。
在计算机领域中,标量通常用于表示简单的数据类型,如整数、浮点数和布尔值等,比如在 Python
中,int
和 float
都是标量类型:
x = 5 # 整数,标量
y = 3.14 # 浮点数,标量
z = True # 布尔值,标量
2. 数组标量(Array Scalar)
Python
只定义了特定数据类的单一类型,在一般的编程场景中,不需要关注数据如何在计算机中表示,但是在在科学计算中,通常需要更多的控制。
NumPy
在基础 Python
类型的基础上提供了 24
种新的不同类型的标量,这些类型描述符大多基于 C
语言中的类型(CPython
是用 C
语言编写的),并且有几个类型与 Python
类型兼容。
从多维数组 (ndarray
) 中提取的单个元素时,返回的是数组标量(array scalars
),不是普通的 Python
数值类型,而是具有与 ndarray
相同的属性和方法的特殊对象,但数组标量是不可变的,因此不能设置任何数组标量的属性,这种设计使得标量和数组之间的操作更加一致。
数据类型的层次结构如下:
图示说明:
- 所有数组标量都继承自基类
np.generic
。 - 数值类数组标量(如整数、浮点数、复数)进一步继承自
np.number
,并分为更细的子类。 - 非数值类型(如字符串、字节、自定义结构)属于
np.flexible
分支,表示可变长度的数据类型。 - 布尔值(
np.bool_
)、日期时间(np.datetime64
、np.timedelta64
)、对象类型(np.object_
)等特殊类型也有自己的层次位置。 - 未显示的是两个整数类型
intp
和uintp
,它们用于索引(与自NumPy 2
以来的默认整数相同)。
某些标量类型本质上等同于 Python
的基础类型,因此既继承自它们,也继承自通用数组标量类型(np.generic
):
数组标量类型 | 关联的 Python 类型 | 是否继承? |
---|---|---|
int_ | int | 仅限 Python 2 |
double | float | 是 |
cdouble | complex | 是 |
bytes_ | bytes | 是 |
str_ | str | 是 |
bool_ | bool | 否 |
datetime64 | datetime.datetime | 否 |
timedelta64 | datetime.timedelta | 否 |
示例 1 ,提取单个元素得到的对象是一个数组标量,支持与 ndarray
相同的属性和方法:
arr = np.array([1, 2, 3], dtype=np.int32)
scalar = arr[0] # 数组标量 np.int32print(scalar.dtype) # 输出: int32
print(scalar.shape) # 输出: ()
print(scalar.item()) # 输出: 1 (Python int)
注意事项:
bool_
数据类型与Python
的bool
非常相似,但不继承自bool
,因为Python
的bool
不允许继承,并且在C
语言层次上,它们的大小不同。int_
在Python 3
中不再继承自int
,int
是任意精度整数(支持大整数),而NumPy
的int_
是固定宽度的。- 当创建
NumPy
数组时,若未指定dtype
,浮点数默认使用float64
(即double
),整数数组的默认类型为int_
(平台相关,通常为int32
或int64
)。
3. 标量类型
3.1 基类
3.1.1 generic
numpy.generic
:所有 NumPy
标量类型的基类。
类定义:
class generic(_ArrayOrScalarCommon, Generic[_ItemT_co]):@abstractmethoddef __init__(self, *args: Any, **kwargs: Any) -> None: ...def __hash__(self) -> int: ...# ......
示例 1 ,通过 isinstance(val, np.generic)
,可以快速判断一个对象是否为 Numpy
数组标量:
val = np.int32(5)
print(isinstance(val, np.generic)) # 输出: Trueval_python = 5
print(isinstance(val_python, np.generic)) # 输出: False
3.1.2 number
numpy.number
:所有数值标量类型(整数、浮点数、复数)的抽象基类。
类定义:
class number(generic[_NumberItemT_co], Generic[_NBit, _NumberItemT_co]):@abstractmethoddef __init__(self, value: _NumberItemT_co, /) -> None: ...def __class_getitem__(cls, item: Any, /) -> GenericAlias: ...def __neg__(self) -> Self: ...def __pos__(self) -> Self: ...def __abs__(self) -> Self: ...# ......
示例 1 ,通过 isinstance(val, np.number)
,可以快速判断一个对象是否为 Numpy
数值标量类型:
val_int = np.int32(5)
val_float = np.float64(3.14)print(isinstance(val_int, np.number)) # True
print(isinstance(val_float, np.number)) # True
3.1.3 flexible
numpy.flexible
:可变长度标量类型的抽象基类。
类定义:
class flexible(_RealMixin, generic[_FlexibleItemT_co], Generic[_FlexibleItemT_co]):
子类:
numpy.character
:numpy.str_
:字符串。numpy.bytes_
:字节类型。
numpy.void
:自定义结构或原始字节数据。
示例 1 , numpy.dtype
参数指定大小:
# 定义长度为 10 的 Unicode 字符串类型(每个字符占 4 字节)
dtype_str = np.dtype('U10') # 总大小 = 10 * 4 = 40 字节
arr_str = np.array(['hello', 'world'], dtype=dtype_str)# 定义长度为 5 的字节字符串类型(固定 5 字节)
dtype_bytes = np.dtype('S5') # 总大小 = 5 字节
arr_bytes = np.array([b'12345', b'abcde'], dtype=dtype_bytes)
3.2 整数类型
抽象基类:
numpy.signedinteger
:所有有符号整数标量类型的抽象基类。numpy.unsignedinteger
:所有无符号整数标量类型的抽象基类。
3.2.1 有符号整数
NumPy 类型 | 字符代码 | 规范名称 | 平台别名(Linux x86_64) | 描述 |
---|---|---|---|---|
numpy.byte | 'b' | numpy.byte | numpy.int8 | 8 位有符号整数(C char ),范围:-128 到 127 |
numpy.short | 'h' | numpy.short | numpy.int16 | 16 位有符号整数(C short ),范围:-32,768 到 32,767 |
numpy.intc | 'i' | numpy.intc | numpy.int32 | 32 位有符号整数(C int ),范围:-2,147,483,648 到 2,147,483,647 |
numpy.int_ | 'l' | numpy.int_ | numpy.int64 numpy.intp | 默认有符号整数类型(64 位系统为 64 位,32 位系统为 32 位) 兼容 C intptr_t (指针大小整数) |
numpy.long | — | — | numpy.int_ | numpy.int_ 的别名 |
numpy.longlong | 'q' | numpy.longlong | — | 64 位有符号整数(C long long ),范围:-9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
3.2.2 无符号整数
NumPy 类型 | 字符代码 | 规范名称 | 平台别名(Linux x86_64) | 描述 |
---|---|---|---|---|
numpy.ubyte | 'B' | numpy.ubyte | numpy.uint8 | 8 位无符号整数(C unsigned char ),范围:0 到 255 |
numpy.ushort | 'H' | numpy.ushort | numpy.uint16 | 16 位无符号整数(C unsigned short ),范围:0 到 65,535 |
numpy.uintc | 'I' | numpy.uintc | numpy.uint32 | 32 位无符号整数(C unsigned int ),范围:0 到 4,294,967,295 |
numpy.uint | 'L' | numpy.uint | numpy.uint64 numpy.uintp | 默认无符号整数类型(64 位系统为 64 位,32 位系统为 32 位) 兼容 C uintptr_t (指针大小无符号整数) |
numpy.ulong | — | — | numpy.uint | numpy.uint 的别名 |
numpy.ulonglong | 'Q' | numpy.ulonglong | — | 64 位无符号整数(C unsigned long long ),范围:0 到 18,446,744,073,709,551,615 |
3.3 不精确类型
抽象基类:
numpy.inexact
:所有不精确数值标量类型(浮点数、复数)的抽象基类。numpy.floating
:所有浮点数标量类型的抽象基类。numpy.complexfloating
:所有复数标量类型(由浮点数组成)的抽象基类。
3.3.1 浮点数
NumPy 类型 | 字符代码 | 规范名称 | 平台别名(Linux x86_64) | 描述 |
---|---|---|---|---|
numpy.half | 'e' | numpy.half | numpy.float16 | 16 位半精度浮点数(1 位符号,5 位指数,10 位尾数)。 |
numpy.single | 'f' | numpy.single | numpy.float32 | 32 位单精度浮点数(1 位符号,8 位指数,23 位尾数),兼容 C float 。 |
numpy.double | 'd' | numpy.double | numpy.float64 | 64 位双精度浮点数(1 位符号,11 位指数,52 位尾数),兼容 Python float 和 C double 。 |
numpy.longdouble | 'g' | numpy.longdouble | numpy.float128 | 扩展精度浮点数(兼容 C long double ,但未必符合 IEEE 754 四倍精度)。 |
3.3.2 复数
NumPy 类型 | 字符代码 | 规范名称 | 平台别名(Linux x86_64) | 描述 |
---|---|---|---|---|
numpy.csingle | 'F' | numpy.csingle | numpy.complex64 | 复数类型,由两个 float32 组成。 |
numpy.cdouble | 'D' | numpy.cdouble | numpy.complex128 | 复数类型,由两个 float64 组成,兼容 Python complex 。 |
numpy.clongdouble | 'G' | numpy.clongdouble | numpy.complex256 | 复数类型,由两个 float128 组成。 |
3.4 其他类型
3.4.1 布尔类型
NumPy 类型 | 字符代码 | 规范名称 | 描述 |
---|---|---|---|
numpy.bool_ | '?' | numpy.bool | 布尔类型(True/False),存储为字节。警告:bool_ 不是 int_ 的子类。 |
3.4.2 日期时间与时间差
NumPy 类型 | 字符代码 | 描述 |
---|---|---|
numpy.datetime64 | 'M' | 表示时间戳(从 1970-01-01T00:00:00 的偏移量或 ISO 8601 字符串)。警告:解析字符串时忽略时区。 |
numpy.timedelta64 | 'm' | 时间差类型,存储为 64 位整数。 |
3.4.3 对象类型
NumPy 类型 | 字符代码 | 描述 |
---|---|---|
numpy.object_ | 'O' | 任意 Python 对象。注意:存储的是对象引用,而非对象本身。 |
3.4.4 灵活类型(无预定义长度)
NumPy 类型 | 字符代码 | 规范名称 | 描述 |
---|---|---|---|
numpy.flexible | — | — | 所有无预定义长度的标量类型的抽象基类(如字符串、字节、自定义结构)。 |
numpy.character | — | — | 所有字符串标量类型的抽象基类。 |
numpy.bytes_ | 'S' | numpy.bytes_ | 字节字符串类型(自动去除末尾空字节)。 |
numpy.str_ | 'U' | numpy.str_ | Unicode 字符串类型(自动去除末尾空字符)。注意:支持缓冲协议,内部存储为 UCS4 。 |
numpy.void | 'V' | numpy.void | 结构化或非结构化二进制数据,需指定长度或数据。 |
4. 对象属性
数组标量数组对象与数组共享大部分属性,但可能表现不同,在逻辑上行为有所区别:
属性 | 描述 | 标量的具体表现 |
---|---|---|
flags | 整数值,表示数据的存储属性(如是否可写、连续性)。 | 不可写:在标量中 flags 直接返回整数,如 WRITEABLE=False |
shape | 数组维度的元组。 | 标量是 0 维,返回空元组:() |
strides | 每个维度中步长的字节数(用于连续内存访问)。 | 标量是 0 维,返回空元组:() |
ndim | 数组的维度数量。 | 0(标量无维度) |
data | 指向元素数据缓冲区的指针(Python 字节对象形式)。 | 存在,但实际用途有限(如 np.int32(5).data 返回包含单个值的缓冲区)。 |
size | 数组或标量中元素的总数。 | 1(标量总是单元素) |
itemsize | 单个元素占用的字节数(如 int32 为 4 字节)。 | 如 np.float64(3.14).itemsize 返回 8 。 |
base | 根据数组是否共享内存,指向原始对象。 | 标量是独立对象,返回 None 。 |
dtype | 数组或标量的数据类型描述符。 | 返回对应的 dtype 对象(如 np.float32 对应 float32 )。 |
real / imag | 复数标量的实部和虚部;非复数标量返回 self 和 0 。 | 如 np.complex128(3+4j).real 返回 3.0 ,.imag 返回 4.0 。 |
flat | 一维迭代器视图。 | 对标量无意义,但仍返回一个生成器(仅能迭代一次,如 next(x.flat) )。 |
T | 转置(对标量而言,没有变化)。 | 返回标量自身。 |
__array_interface__ | Python 层级接口,定义与外部库交互的协议(如数据类型、形状、数据指针)。 | 如 np.int16(5).__array_interface__ 包含键如 'shape' , 'typestr' 。 |
__array_struct__ | C 语言层级接口(PyArrayInterface 结构体),用于直接内存操作。 | 标量支持该接口,便于底层操作。 |
__array_priority__ | 控制混合运算时的优先级(值越高,优先级越高)。标量的优先级为 -1,000,000.0 ,低于数组(默认 0 ),因此标量运算结果被广播为数组。 | 例如:np.array([2]) + 3 结果为数组,而非标量。 |
__array_wrap__ | 自定义对象在运算后的包装行为(可子类化标量时覆盖此方法)。 | 默认返回标量类型。 |
示例:
s = np.float64(3.14) # 标量print("Shape:", s.shape) # 输出: ()
print("Data:", s.data) # 输出: <memory at ...>
print("Size:", s.size) # 输出: 1
print("Dtype:", s.dtype) # 输出: float64
print("Flags:", s.flags) # 输出: 不可写(如 WRITEABLE=False)
print("Real/Imag:", s.real, s.imag) # 输出: 3.14 0.0
5. 对象方法
数组标量的方法与 ndarray
对象的方法完全一致,但其默认行为是将标量隐式转换为 0
维数组后调用数组方法。
通用方法:
方法 | 标量行为 | 示例 |
---|---|---|
squeeze() | 对标量无实际效果(标量本身就是 0 维)。 | np.int32(5).squeeze() 返回自身。 |
byteswap() | 返回字节顺序交换后的新标量(标量不可变)。 | np.int16(0x1234).byteswap() → 0x3412 (新标量)。 |
setflags() | 对标量无效(标量数据不可写)。 | 调用会忽略或引发警告。 |
特殊方法:
方法 | 标量行为 | 用途 |
---|---|---|
__array__(dtype) | 将标量转换为指定 dtype 的 0 维数组。 | 用于类型强制转换:s.__array__('float32') → float32 数组。 |
__array_wrap__() | 控制运算后返回结果的类型(默认返回标量类型)。 | 子类化标量时覆盖此方法可自定义运算结果类型。 |
__reduce__() | 序列化(Pickle)支持,存储重建标量所需的信息。 | pickle.dumps(np.float64(3.14)) 依赖此方法。 |
__setstate__() | 反序列化时恢复标量状态。 | pickle.loads(...) 时调用。 |
类型参数化方法:
方法 | 行为 | 示例 |
---|---|---|
__class_getitem__(item) | 返回参数化的类型包装器(用于泛型类型注解)。 | np.float32.__class_getitem__('DType') → 类型提示元数据。 |
与数组方法的区别:
方法/属性 | 数组行为 | 标量行为 |
---|---|---|
resize() | 修改数组形状。 | 不可用(标量不可变)。 |
fill() | 填充数组元素。 | 不可用(标量不可变)。 |
view(dtype) | 返回数据视图(共享内存)。 | 返回新标量(因标量不可共享内存)。 |
__setitem__ | 支持索引赋值。 | 不可用(标量不可变)。 |
6. 索引
数组标量索引的三种使用方式:
x[()]
:获取标量的副本。x[...]
:转换为0
维数组x['field-name']
:访问结构化字段
示例 1 ,x[()]
将数组标量视为 0
维数组,通过空元组 ()
索引访问其值,返回一个副本:
s = np.int32(5) # 标量
copy_s = s[()] # 返回 int32(5) 的副本
copy_s = 10 # 修改副本
print(s) # 输出: 5(原标量未改变)
示例 2 ,使用省略号 ...
索引,将标量转换为 0
维数组(ndarray
对象):
s = np.float64(3.14)
arr = s[...] # 转换为 0 维数组
print(type(arr)) # 输出: <class 'numpy.ndarray'>
print(arr) # 输出: array(3.14)
示例 3 ,当标量对应结构化数据类型(structured dtype
)时,通过字段名访问其字段值:
# 定义结构化数据类型
dt = np.dtype([('x', 'i4'), ('y', 'f4')])
s = np.array((5, 3.14), dtype=dt)[()] # 创建结构化标量print(s['x']) # 输出: 5(int32 标量)
print(s['y']) # 输出: 3.14(float32 标量)