前言

在使用 NumPy 进行数组与数值计算时,了解数组的形状(shape)和元素个数(size)是非常基础且重要的技能。很多初学者常把 np.size()np.shape() 混淆,或在边界情况下(例如 0-D、非规则列表、或 object 数组)出现错误判断。本文将详细讲解两者的含义、函数与属性的用法、常见陷阱以及实用建议,并配上可直接运行的代码示例与小工具函数,便于测试与使用。


一、核心概念

  • shape(或 np.shape(x))返回形状元组,描述每一轴(axis)的长度,例如 (3, 4)。它表示数组的维度结构。
  • size(或 np.size(x))返回数组中元素的总数(所有轴长度的乘积),例如 12np.size 还支持 axis 参数用于查询某一轴的长度。

二、API 速查表及实例

  • arr.shape —— ndarray 属性,返回 tuple(例如 (m, n))。推荐首选。

  • np.shape(arr) —— 函数,接受任意 array-like,返回形状 tuple。对非规则嵌套序列的行为依赖于 np.array 的转换结果。

  • arr.size —— ndarray 属性,返回元素总数(int)。推荐首选。

  • np.size(arr, axis=None) —— 函数,返回元素总数或指定轴的长度。返回 int。

  • 简单示例

import numpy as np

# 创建 3x4 数组
a = np.arange(12).reshape(3, 4)
print(a)
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]]

print('shape:', a.shape)        # (3, 4)
print('np.shape:', np.shape(a)) # (3, 4)
print('size:', a.size)          # 12
print('np.size:', np.size(a))   # 12
print('np.size(axis=0):', np.size(a, axis=0))  # 3
print('np.size(axis=1):', np.size(a, axis=1))  # 4
print('ndim:', a.ndim)         # 2
print('len(a):', len(a))       # 3 (等同于 shape[0])

三、特殊情况与常见陷阱

1. 0-D(标量)数组

b = np.array(5)       # 0-D
print(b.shape)  # ()
print(b.size)   # 1
# 注意:b.shape[0] 会报错,因为 shape 是空 tuple

处理建议:在访问 shape[0] 之前,先检查 arr.ndim 或使用 len(arr) 仅在确实是至少 1-D 时使用。

2. 不规则(ragged)嵌套列表

c = [ [1, 2], [3, 4, 5] ]
arr = np.array(c)
print(arr)           # array([list([1, 2]), list([3, 4, 5])], dtype=object)
print(arr.shape)     # (2,)   —— 变成了 1-D 的 object 数组

说明:对不规则嵌套列表,np.array 会生成 dtype=object 的一维数组,此时 shape 不反映内部每个子列表长度, 使用 np.shape(c)(直接对 Python list 调用)会根据 Python 对象的序列规则返回 (2,)。小心不要误以为得到 (2, 3)

3. 使用 shape[0] 的风险

当数组可能是 0-D 时,直接用 shape[0] 会抛出 IndexError。防护写法:

if arr.ndim >= 1:
    n_rows = arr.shape[0]
else:
    n_rows = 1   # 或者按需处理标量情况

4. len(arr) 的含义

len(arr) 返回最外层轴(axis 0)的长度,如果是 0-D(标量)数组会报 TypeError。因此 len 只在你确定数组至少是 1-D 时安全使用。


四、性能与使用建议

  • 优先使用属性访问:对于 ndarray,使用 arr.shape / arr.sizenp.shape(arr) / np.size(arr) 更直接且速度更快(属性访问避免函数调用开销)。
  • 明确意图:如果目的是获取“元素总数”,用 arr.size;若目的是“某轴长度”,用 arr.shape[axis]。代码可读性更好,也更不易出错。
  • 对外部/任意 array-like 使用 np.shape:当你接受任意 sequence(list/tuple/array-like)作为输入并需要安全获取形状信息,np.shape(obj) 是通用的。但请谨慎处理 ragged 情况。

五、常见场景 & 推荐写法

场景 1:验证数组是否为空

# 判空:没有元素
if arr.size == 0:
    # 处理空数组
    pass

场景 2:检查是否是向量或矩阵

if arr.ndim == 1:
    # 向量
elif arr.ndim == 2:
    # 矩阵

场景 3:按行/列循环

# 按行遍历(确保至少 2-D 或 1-D)
for i in range(arr.shape[0]):
    row = arr[i]

# 或更 Pythonic:
for row in arr:
    ...

场景 4:需要某轴长度但不确定 ndim

def axis_length(arr, axis=0):
    arr = np.asarray(arr)
    if axis < 0:
        axis = arr.ndim + axis
    if axis < 0 or axis >= arr.ndim:
        raise IndexError('axis out of range')
    return arr.shape[axis]

六、常用语句

  • arr.shape —— 元组,例如 (m, n)
  • arr.size —— 元素总数(int)。
  • len(arr) —— 等同于 arr.shape[0](前提:arr.ndim >= 1)。
  • np.shape(obj) —— 通用函数,适用于 array-like。对 ragged 列表会返回 (n,)。注意 dtype=object
  • np.size(obj, axis=k) —— 返回 axis k 的长度或总元素数。

七、实战示例

shapesize 做参数校验

import numpy as np

def validate_inputs(X, y=None):
    X = np.asarray(X)
    if X.ndim != 2:
        raise ValueError('X must be 2-D (n_samples, n_features)')
    if y is not None:
        y = np.asarray(y)
        if y.size != X.shape[0]:
            raise ValueError('y must have same number of samples as X')
    return X, y

上面示例展示了:用 shape 做结构检查,用 size 做元素计数比较,两者结合能写出稳健的输入校验逻辑。


总结

  • shape 给出数组的结构(每轴长度),size 给出数组的元素数量(所有轴长度的乘积)。二者是不同维度的信息,但常一起使用以编写健壮的数值代码。
  • 推荐风格:对 ndarray 使用 arr.shape / arr.size(优于 np.shape / np.size);当接口接受任意 array-like 时,可用 np.asarray + 属性访问以标准化输入。对 0-D、非规则嵌套列表(ragged)等边界情况要显式处理,避免直接索引 shape[0] 或盲目使用 len
Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐