Why Does `/=` Raise An Error But Not `x = X / Y` With A Read-only Numpy Array?
Solution 1:
As given in Immutable numpy array?, numpy arrays can be explicitly marked read-only.
When you run somearray =/ value
, you're asking that array to be modified, in a way that (for typical mutable objects, like most numpy arrays) changes not just the individual reference, but the object itself; this means all copies of somearray
(including ones internal to the tensorflow library that provided it) are subject to the change.
By contrast, when you run somearray = somearray / value
, you're creating a new object, not modifying the old one, so there's no conflict with somearray
being marked read-only.
The implementation of __itruediv__
in use could return a completely new object instead of modifying a read-only array, thus making =/
on read-only arrays work the same way +=
works for integers; however, this would mean having the operation allocate memory -- potentially expensive; for numpy, it makes sense to not do expensive things unless the author knows they're being done, so people don't write unnecessarily slow code by mistake. (Having the read-only flag significantly change performance and memory usage characteristics of an object would be a fair bit of extra state that a developer needs to keep in their head to write correct code!)
Solution 2:
It has to do with python operator semantics and the principle of least surprise.
- The expression
x = x + 1
is approximately equivalent tox = type(x).__add__(x, 1)
- The expression
x += 1
is approximately equivalent tox = type(x).__iadd__(x, 1)
By convention, __add__
never mutates the object it is invoked on. __iadd__
sometimes does and sometimes doesn't. There are examples of both among Python's built-ins:
int
andstr
are immutable, so always return a new object. The re-assignment step is very important in this case, since otherwise the name wouldn't get bound to the new value.list
adds in-place. The reassignment is effectively a no-op in this case (but it still happens).
Numpy arrays are usually mutable. Operations like +=
, -=
, *=
, /=
, etc. are truly in-place. In fact, they are supported by the same ufuncs that support the regular operations (add
, subtract
, multiply
, true_divide
), using the out
parameter.
The developers had a choice to make for read-only arrays: either change the semantics of __iadd__
, or raise an error. The principle of least surprise dictated the latter: a function should not change its fundamental behavior under certain circumstances without telling you. It's safe to assume that you used __iadd__
rather than __add__
because you wanted an in-place operation. The function notifies you when it can't do that, because the alternative is to do something you specifically didn't ask for.
Post a Comment for "Why Does `/=` Raise An Error But Not `x = X / Y` With A Read-only Numpy Array?"