I was reading this question, about immutable numpy arrays, and in a comment to one of the answers someone shows that the given trick does not work when y = x[:]
is used rather than y = x
.
>>> import numpy as np >>> x = np.array([1]) >>> y = x >>> x.flags.writeable = False >>> y[0] = 5 Traceback (most recent call last): File "<pyshell#42>", line 1, in <module> y[0] = 5 ValueError: assignment destination is read-only >>> del x, y >>> x = np.array([1]) >>> y = x[:] >>> x.flags.writeable = False >>> y[0] = 5 >>> x array([5])
(Python 3.7.2, numpy 1.16.2)
What even is the difference between these two and why do they behave so differently in this specific case?
EDIT: this does not answer my question because it only asks about the situation using lists, I want to know why the numpy ndarray shows this peculiar behavior where depending on the method of copying modifying the data sometimes does and sometimes doesn’t raise an error.
Advertisement
Answer
y = x
just adds another reference to the existing object, no copying here. This is only adding another name for the same object into the local namespace, so it will behave in every way the same as x
.
y = x[:]
creates a shallow copy of the numpy array. This is a new Python object, but the underlying array data in memory will be the same. However, the flags are now independent:
>>> x = np.array([1]) >>> y = x[:] >>> x.flags.owndata, y.flags.owndata (True, False)
The owndata
flag shows that y
is just a view into the data of x
. Setting the writeable flag on x
will not change y
‘s flags, so y
still holds a writeable view into the data of x
.
>>> x.flags.writeable, y.flags.writeable (True, True) >>> x.flags.writeable = False >>> x.flags.writeable, y.flags.writeable (False, True)
Note that if you turn off the writeable
flag before copying x
, then the copy will also have the writeable flag unset, and you will have a read-only shallow copy.