Eri*_*ang 5 python arrays numpy
在 Python 中使用数据类型 numpy 数组时,我遇到了一些困惑。
问题1
我在 python 解释器中执行以下脚本
>>> import numpy as np
>>> L = [1000,2000,3000]
>>> A = np.array(L)
>>> B = A
Run Code Online (Sandbox Code Playgroud)
然后我检查以下事项:
>>> A is B
True
>>> id(A) == id(B)
True
>>> id(A[0]) == id(B[0])
True
Run Code Online (Sandbox Code Playgroud)
没关系。但随后发生了一些奇怪的事情。
>>> A[0] is B[0]
False
Run Code Online (Sandbox Code Playgroud)
但是 A[0] 和 B[0] 怎么可能是不同的东西呢?他们有相同的id!对于 python 中的列表,我们有
>>> LL = [1000,2000,3000]
>>> SS = LL
>>> LL[0] is SS[0]
True
Run Code Online (Sandbox Code Playgroud)
numpy数组的存储方式和list完全不一样?而且我们还有
>>> A[0] = 1001
>>> B[0]
1001
Run Code Online (Sandbox Code Playgroud)
看起来 A[0] 和 B[0] 是相同的对象。
问题2
我复印了一份A。
>>> C = A[:]
>>> C is A
False
>>> C[0] is A[0]
False
Run Code Online (Sandbox Code Playgroud)
没事儿。A和C看起来是相互独立的。但
>>> A[0] = 1002
>>> C[0]
1002
Run Code Online (Sandbox Code Playgroud)
看来A和C并不是独立的?我完全困惑了。
您在问两个完全独立的问题,所以这里有两个答案。
Numpy 数组的数据在内部存储为连续的 C 数组。数组中的每个条目只是一个数字。另一方面,Python 对象需要一些内务数据,例如引用计数和指向类型对象的指针。您不能简单地将原始指针指向内存中的数字。因此,如果您访问单个元素,Numpy 会在 Python 对象中“装箱”一个数字。每次访问元素时都会发生这种情况,因此偶数A[0]和A[0]是不同的对象:
>>> A[0] is A[0]
False
Run Code Online (Sandbox Code Playgroud)
这就是 Numpy 能够以更节省内存的方式存储数组的核心原因:它不会为每个条目存储完整的 Python 对象,而只会在需要时动态创建这些对象。它针对数组上的矢量化操作进行了优化,而不是针对单个元素访问。
当您执行时,C = A[:]您正在为相同的数据创建一个新视图。你不是在复印。然后,您将拥有两个不同的包装对象,分别由A和C指向,但它们由相同的缓冲区支持。base数组的属性指的是最初创建它的数组对象:
>>> A.base is None
True
>>> C.base is A
True
Run Code Online (Sandbox Code Playgroud)
与索引结合使用时,相同数据的新视图特别有用,因为您可以获得仅包含原始数组的某些切片但由相同内存支持的视图。
要实际创建数组的副本,请使用该copy()方法。
更一般地说,您不应该过多地了解 Python 中的对象标识。一般来说,如果x is y为真,你就知道它们确实是同一个对象。但是,如果返回 false,它们仍然可以是同一对象的两个不同代理。