np.array arr.itemsize 与 sys.getsizeof(arr[0])
np.array arr.itemsize vs sys.getsizeof(arr[0])
给定一个数组
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
It seems that itemsize doesn't work properly.
确实如此,不同的结果是由于 Python 对象与 numpy 中的项目不同。
在Python中,一切都是对象。数据为"boxed"。这意味着例如对于 int
,我们得到:
>>> sys.getsizeof(2)
28
也就是28个字节。那是很多。在大多数编程语言中,int
需要两到八个字节。如果它是 32 位 int
,则需要 4 个字节。
但是在Python中,一个对象有很多"context"。比如一些字节用于表示对象的类型等
然而,Numpy 不是 在 Python 中实现的,它不是一个使用 Python 对象本身的库。它更像是一个用 C 实现的库,并且有一个很好的 Python 接口。因此,这意味着列表 [1, 4, 2, 5]
不会存储在 Python 中作为具有四个对 int
对象的引用的列表,而是作为数组存储,通常具有 "unboxed" 元素。所以上面将采用,给定 int
s 每个占用 32 位,4*32 位和一些额外的 space 用于数组周围的 "context"。
项目因此以更 space 有效的方式存储。这使得处理值更容易,因为我们在这里不遵循指针,而是直接遵循值(有一些方法可以将引用存储在 numpy 数组中,但让我们暂时忽略它)。此外,numpy 数组占用的内存比等效的 Python 列表(连同它包含的项目)要少得多。
但是,如果您从 numpy 数组中获取一项,则需要为此创建一个 Python 对象。所以这意味着它将在这里构造一个 numpy.float64
对象,其中包含该值,但又围绕该值构建了很多 "context" 。这会导致使用更多内存。
numpy 构造特定类型对象的数组这一事实也有一些后果。例如,如果您使用 numpy.int16
,那么这意味着不能将大于 32767 的值存储到其中,因为该值不能用 16 位 2 补码表示法表示:
>>> np.int16(32767)
32767
>>> np.int16(32768)
-32768
此外,如果不使用 Python 对象引用或其他一些 "tricks",就不能构造一个包含不同类型对象的数组。 Numpy 构造了一个 int16
数组,这意味着它将 160 位解释为 10 个 16 位数字。在 Python 中,列表本身包含对对象的引用,并且 Python 对象知道它是什么类型,因此这意味着我们可以将引用设置为另一个类型的另一个对象。
给定一个数组
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
It seems that itemsize doesn't work properly.
确实如此,不同的结果是由于 Python 对象与 numpy 中的项目不同。
在Python中,一切都是对象。数据为"boxed"。这意味着例如对于 int
,我们得到:
>>> sys.getsizeof(2)
28
也就是28个字节。那是很多。在大多数编程语言中,int
需要两到八个字节。如果它是 32 位 int
,则需要 4 个字节。
但是在Python中,一个对象有很多"context"。比如一些字节用于表示对象的类型等
然而,Numpy 不是 在 Python 中实现的,它不是一个使用 Python 对象本身的库。它更像是一个用 C 实现的库,并且有一个很好的 Python 接口。因此,这意味着列表 [1, 4, 2, 5]
不会存储在 Python 中作为具有四个对 int
对象的引用的列表,而是作为数组存储,通常具有 "unboxed" 元素。所以上面将采用,给定 int
s 每个占用 32 位,4*32 位和一些额外的 space 用于数组周围的 "context"。
项目因此以更 space 有效的方式存储。这使得处理值更容易,因为我们在这里不遵循指针,而是直接遵循值(有一些方法可以将引用存储在 numpy 数组中,但让我们暂时忽略它)。此外,numpy 数组占用的内存比等效的 Python 列表(连同它包含的项目)要少得多。
但是,如果您从 numpy 数组中获取一项,则需要为此创建一个 Python 对象。所以这意味着它将在这里构造一个 numpy.float64
对象,其中包含该值,但又围绕该值构建了很多 "context" 。这会导致使用更多内存。
numpy 构造特定类型对象的数组这一事实也有一些后果。例如,如果您使用 numpy.int16
,那么这意味着不能将大于 32767 的值存储到其中,因为该值不能用 16 位 2 补码表示法表示:
>>> np.int16(32767)
32767
>>> np.int16(32768)
-32768
此外,如果不使用 Python 对象引用或其他一些 "tricks",就不能构造一个包含不同类型对象的数组。 Numpy 构造了一个 int16
数组,这意味着它将 160 位解释为 10 个 16 位数字。在 Python 中,列表本身包含对对象的引用,并且 Python 对象知道它是什么类型,因此这意味着我们可以将引用设置为另一个类型的另一个对象。