文章目录
- 1. 概述
- 2. 构造函数
- 3. 索引
- 4. 内存布局
- 5. 数组属性
- 5.1 内存布局属性
- 5.2 数据类型
- 5.3 数组接口
- 5.4 `ctypes` 接口
- 5.5 其他属性
- 6. 数组方法
- 6.1 数组转换
- 6.2 形状操作
- 6.3 元素选择与操作
- 6.4 计算相关
- 7. 算术运算、矩阵乘法与比较操作
- 7.1 比较运算符
- 7.2 真值测试
- 7.3 单目运算符
- 7.4 算术运算符
- 7.5 复合赋值运算
- 7.6 矩阵乘法
- 8. 特殊方法
- 8.1 标准库函数支持
- 8.2 基本定制方法
- 8.3 容器协议实现
- 8.4 类型转换方法
- 8.5 字符串表示
- 8.6 类型工具方法
1. 概述
在 NumPy
中有三个描述数组数据的基本对象:
ndarray
( N
维数组):存储多维数据,描述数据在内存中的布局,提供对数据的批量操作接口,如数学运算、索引、广播等。dtype
(数据类型对象):定义单个元素的内存布局和解释方式,支持基本类型、复合类型(结构化数组)和自定义类型。Array Scalar
(数组标量):通过索引访问单个数组元素时,返回一个与 dtype
对应的标量对象,提供与 Python
原生类型兼容的接口,同时保留 NumPy
类型特性。
它们之间的关系示意图:

图示内容解析:
ndarray
本身,包含元数据(Header
)和数据缓冲区两部分。- 数组中元素的类型由一个单独的数据类型对象(
dtype
)指定,每个 ndarray
都与一个数据类型对象相关联。 - 当访问数组中的单个元素时返回的数组标量
Python
对象。
在之前的篇章中,有提到 ndarray
是 NumPy
中最重要的一个类,它表示 N
维数组对象,该对象是用于存放同类型元素的多维数组。接下来我们全面的了解一下 ndarray
,在官方文档中主要提及了以下知识点:
- 构造函数
- 索引
- 内存布局
- 数组属性
- 数组方法
- 算术运算、矩阵乘法和比较操作
- 特殊方法
2. 构造函数
ndarray
提供了一个底层的构造函数,适用于从现有缓冲区(如二进制数据)创建数组或高级优化场景。
函数定义:
np.ndarray(shape, dtype=float, buffer=None, offset=0, strides=None, order='C')
参数说明:
shape
:数组维度。dtype
:元素类型。buffer
:从现有内存缓冲区(如 bytes
、bytearray
)创建数组。offset
:缓冲区中的起始字节偏移量(默认为 0
)。strides
:自定义内存步长。order
:内存布局顺序。
简单示例:
data = np.arange(6, dtype=np.int32).tobytes()
arr = np.ndarray(shape=(2, 3), dtype=np.int32, buffer=data, strides=(8, 4))print(arr)
⚠️ 提示: 大多数场景下,都是通过高层简洁的接口创建数组。
3. 索引
NumPy
根据索引对象的类型划分了三种索引方式:
- 基础索引:只使用索引序号或切片。
- 高级索引:使用整数数组或布尔数组。
- 字段访问:通过字段名访问(结构化数组)。
⚠️ 提示: 之前已经介绍过了基础索引,后续会单独介绍其他的。
4. 内存布局
无论数组维度多高,数据最终存储在连续的一维内存块中,通过索引规则将 N
维坐标转换为内存中的偏移量。
涉及到的关键属性有:
shape
:数组形状。strides
:每个维度上移动一个元素所需的字节数。dtype
:元素类型。
⚠️ 提示: 后续单独介绍内存布局。
5. 数组属性
数组属性是数组的核心组成部分,反映了数组本身的内在信息,NumPy
数组对象(ndarray
)属性分为以下几类:
- 内存布局
- 数据类型
- 其他属性
- 数组接口协议
ctypes
外部函数接口
5.1 内存布局属性
属性名 | 类型 | 描述 |
---|
ndarray.flags | 属性 | 数组内存布局的信息(如连续性、读写权限等) |
ndarray.shape | 属性 | 数组维度组成的元组(例如 (3, 4) 表示 3 行 4 列的二维数组) |
ndarray.strides | 属性 | 遍历数组时,每个维度中步进的字节数组成的元组 |
ndarray.ndim | 属性 | 数组的维度数量(如标量=0,向量=1,矩阵=2) |
ndarray.data | 属性 | 指向数组数据起始位置的 Python 缓冲区对象 |
ndarray.size | 属性 | 数组中元素的总数(等于各维度大小的乘积) |
ndarray.itemsize | 属性 | 单个数组元素的字节长度(如 float64 类型的元素为 8 字节) |
ndarray.nbytes | 属性 | 数组元素消耗的总字节数(等于 size * itemsize ) |
ndarray.base | 属性 | 若数组共享其他对象的内存,则指向基对象;否则为 None |
5.2 数据类型
属性名 | 类型 | 描述 |
---|
ndarray.dtype | 属性 | 数组元素的数据类型(如 int32 , float64 , 或自定义类型) |
5.3 数组接口
属性名/方法名 | 类型 | 描述 |
---|
__array_interface__ | 属性 | 数组接口的 Python 端实现(提供元数据字典) |
__array_struct__ | 属性 | 数组接口的 C 端实现(用于与 C 扩展交互) |
5.4 ctypes
接口
属性名 | 类型 | 描述 |
---|
ndarray.ctypes | 属性 | 简化数组与 ctypes 模块交互的对象(提供指针、形状等底层访问) |
5.5 其他属性
属性名 | 类型 | 描述 |
---|
ndarray.T | 属性 | 转置数组的视图(等价于 np.transpose() ) |
ndarray.real | 属性 | 数组的实部(对复数数组有效) |
ndarray.imag | 属性 | 数组的虚部(对复数数组有效) |
ndarray.flat | 属性 | 数组的一维迭代器(可遍历所有元素) |
⚠️ 提示: 之前已经介绍过常用的数组属性,没有介绍到的会后续涉及到的章节进行详细介绍。
6. 数组方法
数组对象(ndarray
)包含多种操作方法,通常返回数组结果。按功能进行分类的方法有:
6.1 数组转换
方法名 | 类型 | 描述 |
---|
ndarray.item(*args) | 方法 | 将数组的一个元素复制为标准 Python 标量并返回 |
ndarray.tolist() | 方法 | 将数组转换为 a.ndim 层深度的嵌套 Python 列表 |
ndarray.tostring([order]) | 方法 | tobytes 的兼容性别名,行为完全相同 |
ndarray.tobytes([order]) | 方法 | 生成包含数组原始数据字节的 Python bytes 对象 |
ndarray.tofile(fid[, sep, format]) | 方法 | 将数组以文本或二进制(默认)形式写入文件 |
ndarray.dump(file) | 方法 | 将数组的 pickle 序列化保存到指定文件 |
ndarray.dumps() | 方法 | 返回数组的 pickle 序列化字符串 |
ndarray.astype(dtype[, ...]) | 方法 | 创建转换到指定数据类型的数组副本 |
ndarray.byteswap([inplace]) | 方法 | 交换数组元素的字节顺序(大小端转换) |
ndarray.copy([order]) | 方法 | 返回数组的深拷贝 |
ndarray.view([dtype][, type]) | 方法 | 创建共享数据的新视图(可指定数据类型) |
ndarray.getfield(dtype[, offset]) | 方法 | 以特定类型返回数组的字段(内存布局操作) |
ndarray.setflags([write, align, uic]) | 方法 | 设置数组标志(可写性、内存对齐等) |
ndarray.fill(value) | 方法 | 用标量值填充整个数组 |
6.2 形状操作
方法名 | 类型 | 描述 |
---|
ndarray.reshape(shape[, ...]) | 方法 | 返回新形状的数组(数据不变) |
ndarray.resize(new_shape[, refcheck]) | 方法 | 原地修改数组形状和大小 |
ndarray.transpose(*axes) | 方法 | 返回轴转置后的数组视图 |
ndarray.swapaxes(axis1, axis2) | 方法 | 交换两个轴的数组视图 |
ndarray.flatten([order]) | 方法 | 返回展平为一维的数组副本 |
ndarray.ravel([order]) | 方法 | 返回展平为一维的数组视图 |
ndarray.squeeze([axis]) | 方法 | 移除长度为 1 的轴 |
6.3 元素选择与操作
方法名 | 类型 | 描述 |
---|
ndarray.take(indices[, axis, ...]) | 方法 | 从指定索引处提取元素构建新数组 |
ndarray.put(indices, values[, mode]) | 方法 | 将值按索引写入数组的扁平化视图 |
ndarray.repeat(repeats[, axis]) | 方法 | 重复数组元素生成新数组 |
ndarray.choose(choices[, ...]) | 方法 | 用索引数组从多个选择中构造新数组 |
ndarray.sort([axis, kind, order]) | 方法 | 原地排序数组 |
ndarray.argsort([axis, ...]) | 方法 | 返回排序后的元素索引 |
ndarray.partition(kth[, ...]) | 方法 | 部分排序数组(使第 k 个元素处于有序位置) |
ndarray.argpartition(kth[, ...]) | 方法 | 返回部分排序的索引 |
ndarray.searchsorted(v[, ...]) | 方法 | 查找元素应插入的位置以保持有序 |
ndarray.nonzero() | 方法 | 返回非零元素的索引 |
ndarray.compress(condition[, ...]) | 方法 | 按条件沿轴选择切片 |
ndarray.diagonal([offset, ...]) | 方法 | 返回指定对角线元素 |
6.4 计算相关
方法名 | 类型 | 描述 |
---|
ndarray.max([axis, out, ...]) | 方法 | 沿轴返回最大值 |
ndarray.argmax([axis, out, ...]) | 方法 | 返回最大值索引 |
ndarray.min([axis, out, ...]) | 方法 | 沿轴返回最小值 |
ndarray.argmin([axis, out, ...]) | 方法 | 返回最小值索引 |
ndarray.clip([min, max, out]) | 方法 | 限制数组值在 [min, max] 范围内 |
ndarray.conj() | 方法 | 返回所有元素的复共轭 |
ndarray.round([decimals, out]) | 方法 | 返回四舍五入到指定小数位的数组 |
ndarray.trace([offset, ...]) | 方法 | 沿对角线求和 |
ndarray.sum([axis, ...]) | 方法 | 沿轴求和(支持指定数据类型防止溢出) |
ndarray.cumsum([axis, ...]) | 方法 | 沿轴返回累计和 |
ndarray.mean([axis, ...]) | 方法 | 沿轴计算平均值 |
ndarray.var([axis, ...]) | 方法 | 沿轴计算方差 |
ndarray.std([axis, ...]) | 方法 | 沿轴计算标准差 |
ndarray.prod([axis, ...]) | 方法 | 沿轴计算乘积 |
ndarray.cumprod([axis, ...]) | 方法 | 沿轴返回累计乘积 |
ndarray.all([axis, ...]) | 方法 | 检查是否所有元素为 True |
ndarray.any([axis, ...]) | 方法 | 检查是否有任意元素为 True |
7. 算术运算、矩阵乘法与比较操作
基础规则:
- 逐元素操作:所有算术和比较运算均为逐元素操作,返回新的
ndarray
对象。 - 通用函数等价:每个操作均等价于对应的
NumPy
通用函数(ufunc
)。
7.1 比较运算符
运算符(方法名) | 等价表达式 | 描述 |
---|
ndarray.__lt__(value) | self < value | 逐元素小于比较 |
ndarray.__le__(value) | self <= value | 逐元素小于等于比较 |
ndarray.__gt__(value) | self > value | 逐元素大于比较 |
ndarray.__ge__(value) | self >= value | 逐元素大于等于比较 |
ndarray.__eq__(value) | self == value | 逐元素等于比较 |
ndarray.__ne__(value) | self != value | 逐元素不等于比较 |
7.2 真值测试
方法名 | 描述 |
---|
ndarray.__bool__() | 当数组仅含 1 个元素时返回 True ,否则抛出 ValueError |
注意事项:
- 数组的真值测试会调用
ndarray.__bool__
,如果数组中的元素数量不为 1
,会引发错误,因为此类数组的真值是模糊的。在这种情况下,请使用 .any()
或 .all()
来明确表达您的意图。(如果您想检查数组是否为空,可以使用例如 .size > 0
。)
7.3 单目运算符
运算符方法 | 类型 | 描述 |
---|
ndarray.__neg__() | 方法 | 逐元素取负:-self |
ndarray.__pos__() | 方法 | 逐元素取正:+self |
ndarray.__abs__() | 方法 | 逐元素取绝对值 |
ndarray.__invert__() | 方法 | 逐元素按位取反:~self |
7.4 算术运算符
运算符方法 | 类型 | 描述 |
---|
ndarray.__add__(value) | 方法 | 逐元素加法:self + value |
ndarray.__sub__(value) | 方法 | 逐元素减法:self - value |
ndarray.__mul__(value) | 方法 | 逐元素乘法:self * value |
ndarray.__truediv__(value) | 方法 | 逐元素真除法:self / value |
ndarray.__floordiv__(value) | 方法 | 逐元素地板除法:self // value |
ndarray.__mod__(value) | 方法 | 逐元素取模:self % value |
ndarray.__divmod__(value) | 方法 | 返回 (商, 余数) 元组 |
ndarray.__pow__(value[, mod]) | 方法 | 逐元素幂运算(忽略第三个参数) |
ndarray.__lshift__(value) | 方法 | 逐元素左移位:self << value |
ndarray.__rshift__(value) | 方法 | 逐元素右移位:self >> value |
ndarray.__and__(value) | 方法 | 逐元素按位与:self & value |
ndarray.__or__(value) | 方法 | 逐元素按位或:self | value |
ndarray.__xor__(value) | 方法 | 逐元素按位异或:self ^ value |
注意事项:
pow
的第三个参数会被忽略(底层 ufunc
仅接受两个参数)。- 不支持反向运算符(如
__radd__
),需通过 __array_ufunc__
自定义行为。
7.5 复合赋值运算
运算符方法 | 类型 | 描述 |
---|
ndarray.__iadd__(value) | 方法 | 原地加法:self += value |
ndarray.__isub__(value) | 方法 | 原地减法:self -= value |
ndarray.__imul__(value) | 方法 | 原地乘法:self *= value |
ndarray.__itruediv__(value) | 方法 | 原地真除法:self /= value |
ndarray.__ifloordiv__(value) | 方法 | 原地地板除法:self //= value |
ndarray.__imod__(value) | 方法 | 原地取模:self %= value |
ndarray.__ipow__(value) | 方法 | 原地幂运算:self **= value |
ndarray.__ilshift__(value) | 方法 | 原地左移位:self <<= value |
ndarray.__irshift__(value) | 方法 | 原地右移位:self >>= value |
ndarray.__iand__(value) | 方法 | 原地按位与:self &= value |
ndarray.__ior__(value) | 方法 | 原地按位或:self |= value |
ndarray.__ixor__(value) | 方法 | 原地按位异或:self ^= value |
7.6 矩阵乘法
运算符方法 | 类型 | 描述 |
---|
ndarray.matmul(value) | 方法 | 矩阵乘法:self @ value |
8. 特殊方法
8.1 标准库函数支持
方法名 | 类型 | 描述 |
---|
ndarray.__copy__() | 方法 | 实现 copy.copy() 的浅拷贝逻辑 |
ndarray.__deepcopy__(memo) | 方法 | 实现 copy.deepcopy() 的深拷贝逻辑 |
ndarray.__reduce__() | 方法 | 序列化数组(pickling 支持) |
ndarray.__setstate__(state) | 方法 | 反序列化数组(unpickling 支持) |
8.2 基本定制方法
方法名 | 类型 | 描述 |
---|
ndarray.__new__(*args, **kwargs) | 方法 | 构造新数组的工厂方法 |
ndarray.__array__([dtype]) | 方法 | 返回自身引用(当 dtype 匹配时)或副本 |
ndarray.__array_wrap__(array) | 方法 | 返回与自身类型相同的数组视图 |
8.3 容器协议实现
方法名 | 类型 | 描述 |
---|
ndarray.__len__() | 方法 | 返回数组长度(第一维大小) |
ndarray.__getitem__(key) | 方法 | 实现索引操作 self[key] |
ndarray.__setitem__(key, value) | 方法 | 实现赋值操作 self[key] = value |
ndarray.__contains__(key) | 方法 | 实现成员检测 key in self |
8.4 类型转换方法
方法名 | 类型 | 描述 |
---|
ndarray.__int__() | 方法 | 转换为整型(仅单元素数组有效) |
ndarray.__float__() | 方法 | 转换为浮点型(仅单元素数组有效) |
ndarray.__complex__() | 方法 | 转换为复数型(仅单元素数组有效) |
8.5 字符串表示
方法名 | 类型 | 描述 |
---|
ndarray.__str__() | 方法 | 返回用户友好字符串表示(如 print(arr) ) |
ndarray.__repr__() | 方法 | 返回开发者调试用字符串表示 |
8.6 类型工具方法
方法名 | 类型 | 描述 |
---|
ndarray.__class_getitem__(item) | 方法 | 创建参数化类型包装器(用于类型注解) |