关于numpy数组如何存储在Python中的一些混淆

时间:2016-12-01 13:08:51

标签: python arrays numpy

在Python中使用数据类型numpy数组时,我有些困惑。

问题1

我在python intepreter中执行以下脚本

>>> import numpy as np
>>> L = [1000,2000,3000]
>>> A = np.array(L)
>>> B = A

然后我检查以下事项:

>>> A is B
True
>>> id(A) == id(B)
True
>>> id(A[0]) == id(B[0])
True

没关系。但是当时发生了一些奇怪的事情。

>>> A[0] is B[0]
False

但是A [0]和B [0]怎么可能是不同的东西?他们有相同的身份证! 对于python中的List,我们有

>>> LL = [1000,2000,3000]
>>> SS = LL
>>> LL[0] is SS[0]
True

存储numpy数组的方法与list完全不同?我们也有

>>> A[0] = 1001
>>> B[0]
1001

似乎A [0]和B [0]是相同的对象。

问题2

我制作了A的副本。

>>> C = A[:]
>>> C is A
False
>>> C[0] is A[0]
False

没关系。 A和C似乎彼此独立。但

>>> A[0] = 1002
>>> C[0]
1002

似乎A和C不是独立的?我完全糊涂了。

1 个答案:

答案 0 :(得分:3)

你问两个完全独立的问题,所以这里有两个答案。

  1. Numpy数组的数据在内部存储为连续的C数组。数组中的每个条目都只是一个数字。另一方面,Python对象需要一些内务处理数据,例如引用计数和指向类型对象的指针。你不能简单地在内存中有一个指向数字的原始指针。出于这个原因,如果你访问一个单独的元素,Numpy会在Python对象中“装箱”一个数字。每次访问元素时都会发生这种情况,因此即使A[0]A[0]也是不同的对象:

    >>> A[0] is A[0]
    False
    

    这就是为什么Numpy可以以更节省内存的方式存储数组的核心:它不为每个条目存储完整的Python对象,只在需要时动态创建这些对象。它针对阵列上的矢量化操作进行了优化,而不是针对单个元素访问。

  2. 执行C = A[:]时,您正在为相同数据创建新视图。你没有制作副本。然后,您将有两个不同的包装器对象,分别由AC指向,但它们由相同的缓冲区支持。数组的base属性引用它最初创建的数组对象:

    >>> A.base is None
    True
    >>> C.base is A
    True
    

    当与索引结合使用时,对相同数据的新视图特别有用,因为您可以获得仅包含原始数组的某些片段但由相同内存支持的视图。

    要实际制作数组的副本,请使用copy()方法。

  3. 作为一个更一般的评论,你不应该在Python中过多地阅读对象标识。通常,如果x is y为真,则您知道它们实际上是同一个对象。但是,如果返回false,它们仍然可以是同一对象的两个不同代理。