Question

Lets say I have a numpy array like

x = np.arange(10)

is it somehow possible to create a reference to a single element i.e.

y = create_a_reference_to(x[3])
y = 100 
print x
[  0   1   2 100   4   5   6   7   8   9]
Was it helpful?

Solution

You can't create a reference to a single element, but you can get a view over that single element:

>>> x = numpy.arange(10)
>>> y = x[3:4]
>>> y[0] = 100
>>> x
array([0, 1, 2, 100, 4, 5, 6, 7, 8, 9])

The reason you can't do the former is that everything in python is a reference. By doing y = 100, you're modifying what y points to - not it's value.

If you really want to, you can get that behaviour on instance attributes by using properties. Note this is only possible because the python data model specifies additional operations while accessing class attributes - it's not possible to get this behaviour for variables.

OTHER TIPS

No you cannot do that, and that is by design.

Numpy arrays are of type numpy.ndarray. Individual items in it can be accessed with numpy.ndarray.item which does "copy an element of an array to a standard Python scalar and return it".

I'm guessing numpy returns a copy instead of direct reference to the element to prevent mutability of numpy items outside of numpy's own implementation.

Just as a thoughtgame, let's assume this wouldn't be the case and you would be allowed to get reference to individual items. Then what would happen if: numpy was in the midle of calculation and you altered an individual intime in another thread?

@goncalopp gives a correct answer, but there are a few variations that will achieve similar effects.

All of the notations shown below are able to reference a single element while still returning a view:

x = np.arange(10)
two_index_method = [None] * 10
scalar_element_method = [None] * 10
expansion_method = [None] * 10
for i in range(10):
    two_index_method[i] = x[i:i+1]
    scalar_element_method[i] = x[..., i]  # x[i, ...] works, too
    expansion_method[i] = x[:, np.newaxis][i]  # np.newaxis == None

two_index_method[5]  # Returns a length 1 numpy.ndarray, shape=(1,)
# >>> array([5])
scalar_element_method[5]  # Returns a numpy scalar, shape = ()
# >>> array(5)
expansion_method[5]  # Returns a length 1 numpy.ndarray, shape=(1,)
# >>> array([5])
x[5] = 42  # Change the value in the original `ndarray`
x
# >>> array([0, 1, 2, 3, 4, 42, 6, 7, 8, 9])  # The element has been updated
# All methods presented here are correspondingly updated:
two_index_method[5], scalar_element_method[5], expansion_method[5]
# >>> (array([42]), array(42), array([42]))

Since the object in scalar_element_method is a dimension zero scalar, attempting to reference the element contained within the ndarray via element[0] will return an IndexError. For a scalar ndarray, element[()] can be used to reference the element contained within the numpy scalar. This method can also be used for assignment to a length-1 ndarray, but has the unfortunate side effect that it does not dereference a length-1 ndarray to a python scalar. Fortunately, there is a single method, element.item(), that can be used (for dereferencing only) to obtain the value regardless of whether the element is a length one ndarray or a scalar ndarray:

scalar_element_method[5][0]  # This fails
# >>> IndexError: too many indices for array
scalar_element_method[5][()]  # This works for scalar `ndarray`s
# >>> 42
scalar_element_method[5][()] = 6
expansion_method[5][0]  # This works for length-1 `ndarray`s
# >>> 6
expansion_method[5][()]  # Doesn't return a python scalar (or even a numpy scalar)
# >>> array([6])
expansion_method[5][()] = 8  # But can still be used to change the value by reference
scalar_element_method[5].item()  # item() works to dereference all methods
# >>> 8
expansion_method[5].item()
# >>> [i]8

TLDR; You can create a single-element view v with v = x[i:i+1], v = x[..., i], or v = x[:, None][i]. While different setters and getters work with each method, you can always assign values with v[()]=new_value, and you can always retrieve a python scalar with v.item().

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top