2015-11-01 62 views
0

比方说,我有一个numpy阵列a创造b这样的:如何查找具有相同ID的所有变量?

a = np.arange(3) 
b = a 

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

b[0] = 100 

和打印ab,他们id S和.flags

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 

所以,ab看起来相同,它们的id S皆相等如预期。

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

在这种情况下cd不尽相同,因此做他们的id秒;也如预期。

但是,令我困惑的是我从.flags获得的输出:在所有情况下,OWNDATA设置为True。当我看到documentation,我发现:

OWNDATA(O)的阵列拥有它使用存储器或从 另一个目的借用它。

我的主要问题是现在:

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

相关问题:

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

+0

你似乎对Python中的'='做了些什么不清楚。当你做'b = a'时,你没有两个数组。 [这里有一个快速指南,指出这个语言中'='的意思。](http://nedbatchelder.com/text/names.html) – user2357112

+0

感谢您的参考,但问题仍然存在:如何找到所有具有相同的变量IDS? OWNDATA实际使用的是什么? – Cleb

+0

一次只有一个对象具有给定的ID。 – user2357112

回答

3

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

第一个。

我的版本(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函数的单元测试。如果您想了解什么是令人畏惧的任务,那么请仔细考虑两个已知阵列之间的所有可能的重叠条件。

我喜欢看阵列的.__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 

比较id

In [7]: id(a) 
Out[7]: 142453472 
In [9]: id(b) 
Out[9]: 142453472 

别人的无共享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 

这就是我期望的;意见共享内存,副本不。

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 

只是这短短的会议上,我甲肝在locals() 76项。但我可以搜索它匹配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真。假设OWNDATA表示创建新数组对象后的情况,但如果原始引用被重新定义或删除,则不会更改。它很容易过时。

+0

非常感谢这份详细的回复,我今天晚些时候会经历它。 – Cleb

+0

谢谢,这回答了这个问题,因此我赞成并接受它。一般而言,你是正确的:人应该知道自己的变量,但我只需要使用另一个人的代码,不幸的是,这个人并没有关于copy()。现在我真的想确保过滤出可能由此导致的所有可能的问题。但我不得不承认我的问题不是特别清楚,现在我会以另一种方式问... – Cleb

4

作业b=a不会在原始数组a上创建视图,而只是创建对其的引用。换句话说,b只是a的不同名称。变量ab指的是相同的数组,其拥有其数据,使得OWNDATA标志被设置。修改b将修改a

作业b=a.copy()创建原始数组的副本。也就是说,ab指的是单独的数组,它们都拥有它们的数据,以便设置标记OWNDATA。修改b将不会修改a

但是,如果您分配b=a[:],您将创建原始数组的视图,并且b将不拥有其数据。修改b将修改a

shares_memory功能就是你要找的。它在框中表示它:检查数组ab是否具有共享内存,从而相互影响。

+0

感谢您的解释,这是很清楚的(除了OWNDATA部分)。这就是为什么我给了这些例子,并写道我得到了预期的结果。问题在于我是否可以获得一个函数,如果更改会影响另一个变量则返回True,否则返回False。所以在这种情况下:func(b)= True,func(d)= False – Cleb

+0

已更新,解决您的具体问题。 –

+0

谢谢,这个功能的确看起来我在找什么。非常感谢!我upvote你的答案,并可能在稍后接受它取决于其他答案的质量! – Cleb

相关问题