Alex
Alex

Reputation: 2040

Numpy 1D vs nD arrays (index by reference vs. index by value)

So here's an oddity I noticed recently. In the code below I am creating either a 1D or 2D numpy array, extracting out one of the values from the array (position_3), and then assigning the position I extracted from to a different value.

In the 1D case position_3 matches the originally assigned value in the array (i.e. looks like position_3 is a copy from the 1D array) while in the 2D cases position_3 changes upon changing the array (i.e. it looks like position_3 is a reference from the 2D array).

import numpy as np

print "Testing 1D array"

D1_array =  np.array([0,1,2,3,4])
position_3 = D1_array[3]
D1_array[3] = 0

print "Value at position 3 in array: %i"%(D1_array[3]) #: 0 
print "Value at position_3 variable: %i"%(position_3)  #: 3

print "Testing 2D array"
D2_array = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11],[12,13,14]])
position_3 = D2_array[3]
D2_array[3] = [0,0,0]

print "Value at position 3 in array: %s"%(str(D2_array[3])) #: [0,0,0]
print "Value at position_3 variable: %s"%(str(position_3)) #: [0,0,0]

I understand that everything is a reference in Python etc., but what I don't understand is why is this behavior inconsistent between 1D and 2D arrays? It's worth noting that the same comparison with Python lists yields the copy-like behaviour in both cases (i.e. in the 2D array - AKA a nested list - the position_3 variable remains [6,7,8]).

Upvotes: 1

Views: 214

Answers (1)

unutbu
unutbu

Reputation: 879661

Per the docs on Basic Slicing and Indexing:

The simplest case of indexing with N integers returns an array scalar representing the corresponding item....

All arrays generated by basic slicing are always views of the original array. (my emphasis)

So indexing a 1D array with an integer returns an array scalar:

In [32]: D1_array =  np.array([0,1,2,3,4])

In [33]: D2_array = np.array([[0,1,2],[3,4,5],[6,7,8],[9,10,11],[12,13,14]])

In [36]: D1_array[3]
Out[36]: 3

In [37]: type(D1_array[3])   # an array scalar
Out[37]: numpy.int64

If you assign position_3 = D1_array[3] then position_3 holds the value of this array scalar. Modifying the original array with D1_array[3] = 0 does not affect the value of position_3.

In contrast, indexing a 2D array with an integer returns a view:

In [38]: D2_array[3]
Out[38]: array([ 9, 10, 11])

In [40]: type(D2_array[3])
Out[40]: numpy.ndarray

In [42]: D2_array[3].base is D2_array
Out[42]: True

Modifying a view also alters the original array, and modifying the original array also affects the view.

Upvotes: 3

Related Questions