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

2024-04-26 11:13:23 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我有一个numpy数组a,并创建{},如下所示:

a = np.arange(3)
b = a

如果我现在改变b,例如这样

^{pr2}$

并打印ab,它们的id和{}

print a
print a.flags    
print b
print b.flags
print id(a)
print id(b)

我得到

[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

因此,a和{}看起来是一样的,它们的id和预期的一样。在

当我现在使用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)

我明白了

[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

在本例中,c和{}不同,因此它们的id也与预期一样。在

然而,让我困惑的是我从.flags获得的输出:在所有情况下,OWNDATA都被设置为True。当我阅读documentation时,我发现:

OWNDATA (O) The array owns the memory it uses or borrows it from another object.

我现在的主要问题是:

找到指向同一个id(在上面的例子中是a和{})的所有变量的最简单方法是什么,即检查是否存在另一个具有相同id的变量?我原以为OWNDATA会有帮助,但显然不是这样。在

相关问题:

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


Tags: idfalsetruenp情况itflagsprint
2条回答

赋值b=a不在原始数组a上创建视图,而只是创建对它的引用。换句话说,b只是a的不同名称。变量ab都引用拥有其数据的同一数组,因此设置了OWNDATA标志。修改b将修改{}。在

赋值b=a.copy()创建原始数组的副本。也就是说,a和{}分别引用各自的数据数组,从而设置了OWNDATA标志。修改b不会修改a。在

但是,如果进行赋值b=a[:],则将创建原始数组的视图,b将不拥有其数据。修改b将修改{}。在

^{}函数就是您要查找的。它按照方框上的说明执行:检查to数组ab是否具有共享内存,从而相互影响。在

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

先拿第二个。在

我的版本(1.8.2)没有np.shares_memory函数。它有一个np.may_share_memory。在

https://github.com/numpy/numpy/pull/6166是添加shares_memory的拉请求;它的日期是去年8月。所以你必须有全新的numpy才能使用它。请注意,最终测试可能很难,并且可能会发出“TOO hard”错误消息。例如,我想象有一些片共享内存,但是很难通过简单地比较缓冲区起始点来确定。在

https://github.com/numpy/numpy/blob/97c35365beda55c6dead8c50df785eb857f843f0/numpy/core/tests/test_mem_overlap.py是这些memory_overlap函数的单元测试。如果你想知道两个已知阵列之间所有可能的重叠情况是一项多么艰巨的任务,请阅读它。在

我喜欢看数组的.__array_interface__。字典中的一个条目是“data”,它是指向数据缓冲区的指针。指针相同意味着数据是共享的。但一个观点可能会从某个地方开始。如果shares_memeory看到这个指针,我不会感到惊讶。在

相同的id表示两个变量引用同一个对象,但不同的数组对象可以共享一个数据缓冲区。在

所有这些测试都需要查找特定的引用;因此您仍然需要获取某种类型的引用列表。看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 

比较id

^{pr2}$

除了id,其他人都没有共享id。在

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

我不想分享我的记忆。在

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

就在这个简短的会议上,我有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]))]

其他测试也一样。在

我可以用同样的方法搜索ll

In [28]: [n for n,l in enumerate(ll) if id(l)==id(a)]
Out[28]: [0]

我可以在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

虽然我可以在这些简单的情况下预测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

显然没有其他数据引用,但是经过整形的数组并不“拥有”自己的数据。同样的情况也会发生

temp = np.arange(4); temp = temp.reshape(2,2)

我不得不这么做

temp = np.arange(4); temp.shape = (2,2)

使OWNDATA为真。FalseOWNDATA表示在创建新数组对象之后的某个内容,但是如果原始引用被重新定义或删除,则它不会改变。它很容易过时。在

相关问题 更多 >