There are 2 problems - how you define the variables you want to compare, and how to compare them.
Take the second first.
My version (1.8.2) does not have the np.shares_memory function. It has np.may_share_memory .
https://github.com/numpy/numpy/pull/6166 is a transfer request that adds shares_memory ; it dates from August. Therefore, to use it, you will need a new numpy . Please note that the final test is potentially difficult, and it may display the โTOO HARDโ error message. I assume, for example, that there are some slices that share memory, but are difficult to identify by simply comparing the starting points of the buffer.
https://github.com/numpy/numpy/blob/97c35365beda55c6dead8c50df785eb857f843f0/numpy/core/tests/test_mem_overlap.py is a unit test for these memory_overlap functions. Read it if you want to see what a difficult task it is to think about all the possible conditions for overlapping between two known arrays.
I like to watch the .__array_interface__ . One element of this dictionary is โdataโ, which is a pointer to a data buffer. An identical pointer means data sharing. But the performance may begin somewhere down the line. I would not be surprised if shares_memeory looks at this pointer.
An identical id means that 2 variables refer to the same object, but different objects in the array can share a data buffer.
All of these tests require a search for specific links; so you still need to get some kind of list of links. See locals() ?, globals() . What about unnamed references, such as a list of arrays or some kind of custom dictionary?
Ipython run example:
Some variables and links:
In [1]: a=np.arange(10) In [2]: b=a
Compare id :
In [7]: id(a) Out[7]: 142453472 In [9]: id(b) Out[9]: 142453472
None of the others share id except 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
Whatever I expect; views exchange memory, no copies.
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)
With this short session alone, I have 76 elements in locals() . But I can find it to match id with:
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]))]
The same goes for other tests.
I can search ll in the same way:
In [28]: [n for n,l in enumerate(ll) if id(l)==id(a)] Out[28]: [0]
And I could add a layer to the locals() search, checking if the item is a list or a dictionary, and do a search inside that.
So, even if we focus on the testing method, it is easy to find all possible links.
I think the best approach is to simply understand your own use of variables so that you can clearly identify links, opinions, and copies. In selected cases, you can run tests like may_share_memory or compare data. But there is no inexpensive, final test. When in doubt, itโs cheaper to make a copy than to risk writing something. In my years of using numpy I never felt the need for a definitive answer to this question.
I do not find the OWNDATA flag very useful. Consider the above variables
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
While I can predict the value of OWNDATA in these simple cases, its value does not mean shared memory or a common identifier. False assumes that it was created from another array and thus can share memory. But this is just a "can."
I often create an array of patterns by changing the range.
In [40]: np.arange(3).flags['OWNDATA'] Out[40]: True In [41]: np.arange(4).reshape(2,2).flags['OWNDATA'] Out[41]: False
There is no clear reference to the data, but the modified array does not "own" its own data. The same thing will happen with
temp = np.arange(4); temp = temp.reshape(2,2)
I needed to do
temp = np.arange(4); temp.shape = (2,2)
keep OWNDATA true. False OWNDATA means something immediately after creating a new array object, but it does not change if the original link is redefined or deleted. It is easily obsolete.