np.empty仅分配内存不初始化,np.zeros分配后逐字节写0;前者快两个数量级,但仅当立即全覆盖赋值且绝不读取未赋值位置时才安全使用。

np.empty 不初始化内存,np.zeros 要写零
根本区别在底层行为:np.empty 仅调用 mmap 或 malloc 分配虚拟内存页,不执行任何写操作;而 np.zeros 在分配后会逐字节写入 0,对 GB 级数组意味着要刷写数亿到数十亿字节。实测中,创建一个 (10000, 10000) 的 float64 数组,np.empty 耗时约 0.0002 秒,np.zeros 约 0.015 秒——差出两个数量级。
什么时候能安全用 np.empty?
只有满足全部以下条件时才建议替换:
- 你**立刻**会对整个数组做全覆盖赋值(如
a[:] = 42、a[...] = np.random.rand(*a.shape)) - 中间**绝不会**读取未赋值位置(
np.empty返回的值是内存残留垃圾,可能为 NaN、极值或负数) - 该数组生命周期短,不跨函数传递,或接收方明确知道它未初始化
常见误用:用 np.empty 初始化累加器(比如 sum_arr = np.empty(n); sum_arr[i] += x),第一次读取 sum_arr[i] 就得到随机值,结果完全不可控。
dtype 和 order 参数对两者的性能影响一致吗?
影响方式不同:
-
dtype改变的是内存分配总量,对np.empty和np.zeros都有线性影响,但np.zeros的清零耗时还与字节宽度强相关(float64比float32多一倍写操作) -
order('C'或'F')只影响内存布局,不改变初始化逻辑,所以对两者性能差异无放大或缩小作用
例如:np.zeros((10000, 10000), dtype=np.float32) 比同形状 float64 快近一倍;但 np.empty 版本无论 dtype 都几乎不花时间。
替代方案:np.zeros_like 和 np.full 的开销在哪?
它们不是“更高级”的零初始化,而是封装了额外逻辑:
-
np.zeros_like(arr)先检查arr的shape和dtype,再调用np.zeros—— 多一次属性访问和类型判断,微小开销,可忽略 -
np.full(shape, val)底层先调用np.empty,再用np.copyto或循环填充,比np.zeros略慢;若val == 0,它其实等价于np.zeros,但没做这个优化
真正要注意的是:别为了“语义清晰”在热循环里反复调用 np.zeros_like,尤其当 arr 是局部变量时,它的 .shape 访问本身就有缓存成本。
实际项目里最常被忽略的一点:即使你选了 np.empty,只要后续赋值不是全量覆盖(比如只填前 10% 行),那剩下的 90% 内存仍是垃圾——而这些区域一旦被传给 C 扩展(如 SciPy 函数),可能直接触发段错误或静默计算错误。安全永远比省几毫秒重要。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











