首页 > 解决方案 > 列表和 NumPy 数组内存大小的区别

问题描述

我听说 Numpy 数组比 python 内置列表更有效,并且它们占用的内存空间更少。据我了解,Numpy 将这些对象彼此相邻地存储在内存中,而列表的 python 实现存储指向给定值的 8 个字节指针。但是,当我尝试在 jupyter notebook 中进行测试时,发现两个对象的大小相同。

import numpy as np
from sys import getsizeof
array = np.array([_ for _ in range(4)])
getsizeof(array), array

返回(128, array([0, 1, 2, 3])) 同:

l = list([_ for _ in range(4)])
getsizeof(l), l

(128, [0, 1, 2, 3])

你能提供任何明确的例子来说明我如何在 jupyter notebook 中展示它吗?

标签: pythonarrayslistnumpy

解决方案


getsizeof不是衡量内存使用的好方法,尤其是列表。正如您所注意到的,该列表有一个指针缓冲区,指向内存中其他地方的对象。 getsizeof注意缓冲区的大小,但没有告诉我们有关对象的任何信息。

In [66]: list(range(4))
Out[66]: [0, 1, 2, 3]

该列表有它的基本对象存储,加上带有 4 个指针的缓冲区(加上一些增长空间)。这些数字存储在其他地方。在这种情况下,数字很小,并且已经由解释器创建和缓存。所以他们的存储不会增加任何东西。但是每次使用都会创建更大的数字(和浮点数),并占用空间。列表也可以包含任何内容,例如指向其他列表的指针、字符串或字典,或任何其他内容。

In [67]: arr = np.array([i for i in range(4)])   # via list
In [68]: arr
Out[68]: array([0, 1, 2, 3])
In [69]: np.array(range(4))            # more direct
Out[69]: array([0, 1, 2, 3])
In [70]: np.arange(4)
Out[70]: array([0, 1, 2, 3])           # faster

arr也有一个基本的对象存储,具有形状和 dtype 等属性。它也有一个数据缓冲区,但是对于像这样的数字 dtype,该缓冲区具有实际数值(8 字节整数),而不是指向 Python 整数对象的指针。

In [71]: arr.nbytes
Out[71]: 32

该数据缓冲区仅占用 32 个字节 - 4*8。

对于这个小例子,getsizeof返回相同的东西并不奇怪。基本对象存储比存储 4 个值的位置更重要。当使用 1000 个值和多维数组时,内存使用明显不同。

但更重要的是计算速度。使用数组,您可以执行类似的操作arr+1arr.sum()。它们在编译后的代码中运行,并且速度非常快。类似的列表操作必须以较慢的 Python 速度进行迭代,尽管指针、获取值等。但是对数组进行相同类型的迭代甚至更慢。

作为一般规则,如果您从列表开始,然后执行列表操作(如append和列表推导式),最好坚持使用它们。

但是,如果您可以创建一次数组,或者从其他数组创建,然后使用numpy方法,您将获得 10 倍的速度提升。数组确实更快,但前提是您以正确的方式使用它们。它们不是列表的简单替代品。


推荐阅读