Cle*_*leb 1 python arrays numpy copy
假设我有一个numpy数组a并b像这样创建:
a = np.arange(3)
b = a
Run Code Online (Sandbox Code Playgroud)
如果我现在改变b例如这样
b[0] = 100
Run Code Online (Sandbox Code Playgroud)
并打印a, b, 他们的ids 和.flags
print a
print a.flags
print b
print b.flags
print id(a)
print id(b)
Run Code Online (Sandbox Code Playgroud)
我得到
[100 1 2]
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
[100 1 2]
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
139767698376944
139767698376944
Run Code Online (Sandbox Code Playgroud)
所以,aandb看起来一样,它们的ids 和预期的一样。
当我现在使用 copy()
c = np.arange(3)
d = c.copy()
d[0] = 20
print c
print c.flags
print id(c)
print d
print d.flags
print id(d)
Run Code Online (Sandbox Code Playgroud)
我得到
[0 1 2]
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
139767698377344
[20 1 2]
C_CONTIGUOUS : True
F_CONTIGUOUS : True
OWNDATA : True
WRITEABLE : True
ALIGNED : True
UPDATEIFCOPY : False
139767698376864
Run Code Online (Sandbox Code Playgroud)
在这种情况下,c和d不同,他们的ids也是如此;也符合预期。
但是,令我困惑的是我从 获得的输出.flags:在所有情况下,OWNDATA都设置为True. 当我阅读文档时,我发现:
OWNDATA (O) 数组拥有它使用的内存或从另一个对象借用它。
我现在的主要问题是:
什么是要找到所有的变量指向同一个最简单的方法id(在上面的例子中a和b),即检查与相同ID的另一个变量是否存在?我认为OWNDATA这会有所帮助,但显然不是。
相关问题:
OWNDATA实际用于什么,在哪种情况下OWNDATA设置为False?
有两个问题 - 如何确定要比较的变量,以及如何比较它们。
先拿第二个。
我的版本 (1.8.2) 没有np.shares_memory功能。它确实有一个np.may_share_memory.
https://github.com/numpy/numpy/pull/6166是添加的拉取请求shares_memory;它的日期是去年八月。所以你必须有全新的numpy才能使用它。请注意,确定性测试可能很困难,并且可能会发出“太难”错误消息。我想象,例如,有一些切片共享内存,但很难通过简单地比较缓冲区起点来识别。
https://github.com/numpy/numpy/blob/97c35365beda55c6dead8c50df785eb857f843f0/numpy/core/tests/test_mem_overlap.py是这些memory_overlap函数的单元测试。如果您想了解考虑 2 个已知数组之间所有可能的重叠条件是一项多么艰巨的任务,请阅读它。
我喜欢看数组的.__array_interface__. 该字典中的一项是“数据”,它是指向数据缓冲区的指针。相同的指针意味着数据是共享的。但是视图可能会从某个地方开始。如果shares_memeory看这个指针,我不会感到惊讶。
相同id意味着 2 个变量引用同一个对象,但不同的数组对象可以共享一个数据缓冲区。
所有这些测试都需要查看特定的参考资料;所以你仍然需要获得某种参考列表。看看locals()?,globals()。未命名的引用(例如数组列表或某些用户定义的字典)呢?
一个示例 Ipython 运行:
一些变量和引用:
In [1]: a=np.arange(10)
In [2]: b=a # reference
In [3]: c=a[:] # view
In [4]: d=a.copy() # copy
In [5]: e=a[2:] # another view
In [6]: ll=[a, a[:], a[3:], a[[1,2,3]]] # list
Run Code Online (Sandbox Code Playgroud)
比较id:
In [7]: id(a)
Out[7]: 142453472
In [9]: id(b)
Out[9]: 142453472
Run Code Online (Sandbox Code Playgroud)
其他的无共享id,除了ll[0]。
In [10]: np.may_share_memory(a,b)
Out[10]: True
In [11]: np.may_share_memory(a,c)
Out[11]: True
In [12]: np.may_share_memory(a,d)
Out[12]: False
In [13]: np.may_share_memory(a,e)
Out[13]: True
In [14]: np.may_share_memory(a,ll[3])
Out[14]: False
Run Code Online (Sandbox Code Playgroud)
这就是我所期望的;视图共享内存,副本不共享。
In [15]: a.__array_interface__
Out[15]:
{'version': 3,
'data': (143173312, False),
'typestr': '<i4',
'descr': [('', '<i4')],
'shape': (10,),
'strides': None}
In [16]: a.__array_interface__['data']
Out[16]: (143173312, False)
In [17]: b.__array_interface__['data']
Out[17]: (143173312, False)
In [18]: c.__array_interface__['data']
Out[18]: (143173312, False)
In [19]: d.__array_interface__['data']
Out[19]: (151258096, False) # copy - diff buffer
In [20]: e.__array_interface__['data']
Out[20]: (143173320, False) # differs by 8 bytes
In [21]: ll[1].__array_interface__['data']
Out[21]: (143173312, False) # same point
Run Code Online (Sandbox Code Playgroud)
就在这个简短的会议中,我有 76 个项目locals()。但我可以搜索它以匹配id:
In [26]: [(k,v) for k,v in locals().items() if id(v)==id(a)]
Out[26]:
[('a', array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])),
('b', array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]))]
Run Code Online (Sandbox Code Playgroud)
其他测试也一样。
我可以ll用同样的方式搜索:
In [28]: [n for n,l in enumerate(ll) if id(l)==id(a)]
Out[28]: [0]
Run Code Online (Sandbox Code Playgroud)
我可以locals()通过测试一个项目是列表还是字典,并在其中进行搜索来为搜索添加一个层。
因此,即使我们确定了测试方法,搜索所有可能的参考也并非易事。
我认为最好的方法是只了解您自己对变量的使用,这样您就可以清楚地识别引用、视图和副本。在选定的情况下,您可以执行类似may_share_memory或比较数据缓冲区的测试。但是没有一种廉价的、确定的测试。如有疑问,制作副本比冒险写东西更便宜。在我多年的numpy使用中,我从未觉得需要对这个问题给出明确的答案。
我觉得这个OWNDATA标志不是很有用。考虑上述变量
In [35]: a.flags['OWNDATA']
Out[35]: True
In [36]: b.flags['OWNDATA'] # ref
Out[36]: True
In [37]: c.flags['OWNDATA'] # view
Out[37]: False
In [38]: d.flags['OWNDATA'] # copy
Out[38]: True
In [39]: e.flags['OWNDATA'] # view
Out[39]: False
Run Code Online (Sandbox Code Playgroud)
虽然我可以预测OWNDATA这些简单情况下的值,但它的值并没有说明共享内存或共享 ID。 False表明它是从另一个数组创建的,因此可以共享内存。但这只是“可能”。
我经常通过重塑一个范围来创建一个样本数组。
In [40]: np.arange(3).flags['OWNDATA']
Out[40]: True
In [41]: np.arange(4).reshape(2,2).flags['OWNDATA']
Out[41]: False
Run Code Online (Sandbox Code Playgroud)
显然没有对数据的其他引用,但重构的数组不“拥有”自己的数据。同样会发生
temp = np.arange(4); temp = temp.reshape(2,2)
Run Code Online (Sandbox Code Playgroud)
我不得不做
temp = np.arange(4); temp.shape = (2,2)
Run Code Online (Sandbox Code Playgroud)
保持OWNDATA真实。FalseOWNDATA意味着在创建新数组对象后立即发生某些事情,但如果重新定义或删除原始引用,它不会改变。它很容易过时。
| 归档时间: |
|
| 查看次数: |
205 次 |
| 最近记录: |