As I was looking at some issues related to how Numpy indexing works (sometimes a view, sometimes a copy), I encountered an example in the Numpy docs, which baffles me a bit. Specifically, it can be found here.
Very simplistically, I don't understand the reason why the following snippet
import numpy as np
x = np.arange(2)
x[[0, 0]] += 1
print(x)
produces the result that it does.
I understand that the reason you get what you get is that x[[0, 0]] += 1 seems to expand to something like x.setitem(x.getitem([0, 0]).iadd(1)), but I don't understand why that's the case (you can test that this is what happens if you subclass ndarray and add messages to the relevant methods).
Given the precedence rules, isn't the statement x[[0, 0]] += 1 first converted to x[[0, 0]] = x[[0, 0]] + 1, which means the subsequent expansion should look more likex.getitem([0, 0]).setitem(x.getitem([0, 0]).iadd(1))? I appreciate that this would be awkward, but I don't really understand the formal logic that produces the expansion that allows the modification of the original array.
Is there an implicit binding that takes precedence over subscription?
I tried
import numpy as np
class A(np.ndarray):
def __getitem__(self, *args, **kwargs):
print("getitem")
r = np.ndarray.__getitem__(self, *args, **kwargs)
return r
def __setitem__(self, *args, **kwargs):
print("setitem")
r = np.ndarray.__setitem__(self, *args, **kwargs)
return r
def __iadd__(self, *args, **kwargs):
print("iadd")
r = np.ndarray.__iadd__(self, *args, **kwargs)
return r
nd = np.arange(2)
x = nd.view(A)
x[[0, 0]] += 1
print(x)
A bit more digging makes it even more puzzling, as far as I am concerned.
I used ast to look at what the interpreter does with the following block:
The full output is:
The line that shows the expansion of
x[[0,0]] += 1, formatted to the best of my ability, is:So, based on this, the target for the AugAssign should be the result of the Subscript operation, so how does it end up being
x.setitem(x.getitem([0, 0]).iadd(1))? This still doesn't make sense...