np.array arr.itemsize与sys.getsizeof(arr [0])

时间:2018-11-04 14:44:15

标签: python numpy types numpy-ndarray

给出一个数组

arr = array([  9.93418544e+00,   1.17237323e+01,   1.34554537e+01,
         2.43598467e+01,   2.72818286e+01,   3.11868750e+01,...])

在执行以下命令时,我会得到一些输出:

arr.itemsize # 8
type(arr[0]) # numpy.float64
sys.getsizeof(np.float64()) # 32
sys.getsizeof(arr[0]) # 32
arr.dtype # dtype('float64')

似乎itemsize无法正常工作。我有兴趣为什么会这样?

我与

print(sys.version)
3.5.5 | packaged by conda-forge | (default, Jul 24 2018, 01:52:17) [MSC v.1900 64 bit (AMD64)]
numpy==1.10.4

1 个答案:

答案 0 :(得分:1)

  

项目大小似乎无法正常工作。

确实如此,结果不同是由于Python对象与numpy中的项目不同。

在Python中,一切都是对象。数据被“装箱”。这意味着例如对于int,我们得到:

>>> sys.getsizeof(2)
28

那是28个字节。好多在大多数编程语言中,int占用2到8个字节。如果它是32位的int,则需要4个字节。

但是在Python中,一个对象有很多“上下文”。例如,某些字节用于表示对象的类型,等等。

但是Numpy并不是在Python中实现的,它不是一个使用Python对象本身的库。它更多是用C语言实现的库,并且具有与Python的良好接口。因此,这意味着列表[1, 4, 2, 5]在Python中不是作为具有四个对int对象的引用的列表存储的,而是作为数组存储的,通常带有“未装箱”元素。因此,假设int分别占用32位,4 * 32位和用于数组周围“上下文”的一些额外空间,则上述操作将需要。

因此,项目以更节省空间的方式存储。这使处理值更加容易,因为我们在这里不直接遵循指针,而是直接遵循值(有一些将引用存储在numpy数组中的方法,但让我们暂时忽略它)。此外,numpy数组占用的内存远远少于等效的Python列表(连同它包含的项)的内存。

但是,如果您从numpy数组中获取一项,则需要为此创建一个Python对象。因此,这意味着它将在此处构造一个numpy.float64对象,该对象包含该值,但又围绕该值包含许多“上下文”。这样会占用更多的内存。

numpy构造了某种对象类型的数组这一事实也有一些后果。例如,如果您使用numpy.int16,则意味着不能将大于32767的值存储到其中,因为该值不能用16位2补码表示。

>>> np.int16(32767)
32767
>>> np.int16(32768)
-32768

此外,如果不使用Python对象引用或其他“技巧”,就不能构造一个包含不同类型对象的数组。例如,Numpy构造了int16的数组,这意味着它会将160位解释为10个16位数字。在Python中,列表本身包含对对象的引用,而Python对象知道其类型,因此这意味着我们可以将引用设置为另一种类型的另一个对象。