关于 python 何时自动创建数组副本的文档
Posted
技术标签:
【中文标题】关于 python 何时自动创建数组副本的文档【英文标题】:Documentation on when python automatically creates array copies 【发布时间】:2019-06-30 09:47:12 【问题描述】:我正在尝试查找有关 python 何时自动复制 numpy 数组的文档。这与数组视图有关。
如果使用简单索引,则赋值会生成数组视图。如果使用高级索引,python 会创建一个副本。我发现其他时候 python 制作数组副本,但无法找到文档。这是一个例子:
a = np.array([1.,2.,3.,4.,5.])
av = a.view()
print(a)
print(av)
a[0] = 100.0
print(av)
a = 0
print(av)
变量 av 是 a 的视图,直到 a 发生足够的变化以至于它不再是视图。这是在哪里记录的?
【问题讨论】:
This Numpy copies & views tutorial 可能是了解正在发生的事情的最佳方式。av
是原始 a
的 view
。 a=0
将一个新对象分配给变量a
。该更改与numpy
查看/复制问题无关。
谢谢。曾经,av 是变量 a 的一种视图。进行新分配后, av 不再是视图。我正在尝试查找有关 python 如何将视图更改为其他内容以及触发它的文档的文档。它必须是某种逻辑来跟踪 av 是什么视图。然后,当那件事发生变化时,它会改变 av。我正在尝试了解的有趣逻辑。
【参考方案1】:
In [118]: a = np.array([1.,2.,3.,4.,5.])
...: av = a.view()
In [119]: a
Out[119]: array([1., 2., 3., 4., 5.])
In [120]: av
Out[120]: array([1., 2., 3., 4., 5.])
数组是具有dtype
和shape
等属性的对象,以及指向数据缓冲区的指针 (base
)。我们可以通过以下方式获得这些属性的摘要:
In [121]: a.__array_interface__
Out[121]:
'data': (69293648, False),
'strides': None,
'descr': [('', '<f8')],
'typestr': '<f8',
'shape': (5,),
'version': 3
av
是一个新的数组对象,但它具有相同的属性,包括data
:
In [122]: av.__array_interface__
Out[122]:
'data': (69293648, False), # same value as for a
'strides': None,
'descr': [('', '<f8')],
'typestr': '<f8',
'shape': (5,),
'version': 3
与copy
比较:
In [123]: bv = a.copy()
In [124]: bv.__array_interface__
Out[124]:
'data': (77843920, False),
'strides': None,
'descr': [('', '<f8')],
'typestr': '<f8',
'shape': (5,),
'version': 3
其他视图可能有不同的值 - 切片具有不同的形状和步幅等。但数据缓冲区将是相同的(__array_interface__['data']
中显示的实际数字可能会有点不同,指向缓冲区中的不同元素。
更改a
的元素,我们也看到av
中的更改 - 因为共享数据缓冲区:
In [125]: a[0] =12
In [126]: av[0]
Out[126]: 12.0
In [127]: bv[0]
Out[127]: 1.0
当您将其他内容分配给 a
时,av
不会改变。
In [128]: a = 10
In [129]: a.__array_interface__
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-129-3b348559b028> in <module>
----> 1 a.__array_interface__
AttributeError: 'int' object has no attribute '__array_interface__'
In [130]: av.__array_interface__
Out[130]:
'data': (69293648, False),
'strides': None,
'descr': [('', '<f8')],
'typestr': '<f8',
'shape': (5,),
'version': 3
a
是一个整数,而不是一个数组。最初为a
创建的数据缓冲区仍然存在,作为av
的基础。否则原来的a
对象就消失了。
我需要限定最后一条语句 - 由于 ipython
的输出缓冲,该数组对象仍然存在:
In [131]: Out[119].__array_interface__
Out[131]:
'data': (69293648, False),
'strides': None,
'descr': [('', '<f8')],
'typestr': '<f8',
'shape': (5,),
'version': 3
In [132]: Out[119][0]
Out[132]: 12.0
我可能应该显示id(a)
等,以澄清
In [133]: id(av)
Out[133]: 139992523130800
In [134]: id(Out[119])
Out[134]: 139992142353312
av
的更改出现在 Out[119]
中,但不在 a
中 - 因为 a
是一个完全不同的对象。
In [144]: av[1] = 100
In [145]: Out[119]
Out[145]: array([ 12., 100., 3., 4., 5.])
In [146]: a
Out[146]: 10
因此,在某种程度上,您需要了解 Python 变量和对象的本质。例如,b=a
只是创建另一个名称或对同一对象的引用,而不是副本。 b = a.copy()
制作一个副本,但该副本的详细信息取决于对象类。 numpy
在copy
上添加了一个变体view
,可以节省时间和内存。但是你必须了解它的数据存储机制才能理解它。
【讨论】:
【参考方案2】:来自Advanced Indexing 的 NumPy 文档:
在选择对象,OBJ是非元组序列对象,NDARRAY(数据类型整数或BOOL)或具有至少一个序列对象或NDARRAY(数据类型整数)的元组时触发高级索引布尔)。高级索引有两种类型:整数和布尔值。
高级索引始终返回数据的副本(与返回视图的基本切片相反)。
您可以使用属性base 来检查 ndarray 是另一个副本还是另一个视图。
a = np.arange(0, 10)
b = a.view()
print(b.base is a) # True
c, d = a[2:], a[::2]
print(c.base is a and d.base is a) # True
b = a.copy()
print(b.base is a) # False
b = a[a >= 5]
print(b.base is a) # False
编辑: 我发现有趣的是,您可以为数组“a”创建视图“b”,然后更改原始数组内存地址(使用 resize 方法)。 a 的视图 'base' 属性仍然指向 b,但 b 上的更改不会反映在 a 上:
a = np.arange(0, 10)
b = a.view()
print(np.shares_memory(a, b)) # True
print(b.base is a) # True
a.resize(50, refcheck=False)
print(np.shares_memory(a, b)) # False
print(b.base is a) # True
b[0] = 20
print(a[0] == b[0]) # False
您可以做的另一个技巧是手动更改视图的“数据”属性。如果你这样做,'base' 属性会改变:
a, b = np.arange(0, 10), np.arange(10, 20)
c = a.view()
print(c.base is a) # True
c.data = b.data
print(c.base is a) # False
print(c.base is b) # False
print(c[0]) # 10
print(c.base) # 'Memory at ....'
print(c.base == c.data == b.data) # True
【讨论】:
谢谢。我知道有关索引的文档。我还没有找到关于 python 如何动态地将某些内容从视图更改为非视图的文档。 av 是一种观点。然后它就不是一个视图。这可以按照您的建议使用 base 进行验证。但是,它与切片无关。以上是关于关于 python 何时自动创建数组副本的文档的主要内容,如果未能解决你的问题,请参考以下文章
SQL Server 2017 AlwaysOn AG 自动初始化
SQL Server 2017 AlwaysOn AG 自动初始化