Reputation: 28903
Is there a general rule of thumb for knowing which operations on a numpy.ndarray
produce a copy of the values and which mutate them in-place?
I'm pretty new to numpy and I'm sure I'll learn the hard way eventually, but I was wondering if there were general principles driving mutability that might help speed my learning.
Upvotes: 4
Views: 1009
Reputation: 13999
Relatively few numpy functions mutate in place. For the most part, numpy functions return array views when they can, and copies when they can't.
Here's an exhaustive list (trawled from the docs) of functions/methods that mutate in place:
ndarray.resize
ndarray.sort
+=
, *=
, ^=
, etc)numpy.fill_diagonal
numpy.random.shuffle
ndarray.partition
and here's a list of the functions/methods that can optionally mutate in place:
ndarray.byteswap
numpy.nan_to_num
Certain assignments will also mutate an array in place. You can change the values in an array by assigning to a slice (eg arr[...] = 1
will set every value in an array to 1
), and you can reshape an array by assigning a new shape directly to .shape
, eg arr.shape = (2,3)
(won't always work, see notes here).
There's also some functions that support an out
keyword arg. These functions will behave as mutators if you pass the same array as both input and out
.
Fair warning, I may have missed one or two mutators that weren't clearly marked in the docs. In any case, the list is short, so there's not much to memorize.
One of the goals of the numpy devs over the last few years seemingly has been to make it more common for the numpy functions and the ndarray
methods to return views instead of copies. At this point, it's reasonably safe to assume that if a numpy function/method can return a view, it will do so by default.
For example, ndarray.flatten
and ndarray.ravel
do the same thing (returned a flattened array). However, the docs for ndarray.flatten
explicitly say that it will return a copy, whereas the docs for ndarray.ravel
say that it will return a copy only if absolutely necessary.
In live code, as a rule of thumb you can always check if an operation produced a view or a copy by comparing the id
of the .base
of your result to the id
of original array. For example:
arr = np.array([[1, 2],
[3, 4],
[5, 6]])
arrflat = arr.flatten()
assert arrflat.base is not arr
arrravel = arr.ravel()
assert arrravel.base is arr
Upvotes: 7