如何找到所有具有相同ID的变量?

Cle*_*leb 1 python arrays numpy copy

假设我有一个numpy数组ab像这样创建:

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)

在这种情况下,cd不同,他们的ids也是如此;也符合预期。

但是,令我困惑的是我从 获得的输出.flags:在所有情况下,OWNDATA都设置为True. 当我阅读文档时,我发现:

OWNDATA (O) 数组拥有它使用的内存或从另一个对象借用它。

我现在的主要问题是:

什么是要找到所有的变量指向同一个最简单的方法id(在上面的例子中ab),即检查与相同ID的另一个变量是否存在?我认为OWNDATA这会有所帮助,但显然不是。

相关问题:

OWNDATA实际用于什么,在哪种情况下OWNDATA设置为False

hpa*_*ulj 5

有两个问题 - 如何确定要比较的变量,以及如何比较它们。

先拿第二个。

我的版本 (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意味着在创建新数组对象后立即发生某些事情,但如果重新定义或删除原始引用,它不会改变。它很容易过时。