How do they achieve internally that you are able to pass something like x > 5 into a method?
The short answer is that they don't.
Any sort of logical operation on a numpy array returns a boolean array. (i.e. __gt__, __lt__, etc all return boolean arrays where the given condition is true).
This is the same reason why something like if x > 5: raises a ValueError if x is a numpy array. It's an array of True/False values, not a single value.
Furthermore, numpy arrays can be indexed by boolean arrays. E.g. x[x>5] yields [6 7 8], in this case.
Honestly, it's fairly rare that you actually need numpy.where but it just returns the indicies where a boolean array is True. Usually you can do what you need with simple boolean indexing.
np.where returns a tuple of length equal to the dimension of the numpy ndarray on which it is called (in other words ndim) and each item of tuple is a numpy ndarray of indices of all those values in the initial ndarray for which the condition is True. (Please don't confuse dimension with shape)
y is a tuple of length 2 because x.ndim is 2. The 1st item in tuple contains row numbers of all elements greater than 4 and the 2nd item contains column numbers of all items greater than 4. As you can see, [1,2,2,2] corresponds to row numbers of 5,6,7,8 and [2,0,1,2] corresponds to column numbers of 5,6,7,8
Note that the ndarray is traversed along first dimension(row-wise).
Similarly,
x=np.arange(27).reshape(3,3,3)
np.where(x>4)
will return a tuple of length 3 because x has 3 dimensions.
But wait, there's more to np.where!
when two additional arguments are added to np.where; it will do a replace operation for all those pairwise row-column combinations which are obtained by the above tuple.
I had a tough time understanding the output, that I received for an input.
import numpy as np
pp = np.array([[True,False,True,True],
[False,True,False,True]])
np.where(pp)
The output was:
(array([0, 0, 0, 1, 1]), array([0, 2, 3, 1, 3]))
The best way to understand this is to read out the output tuple pair by pair, i.e. (0,0);(0,2);(0,3);(1,1);(1,3) and voila, these are the coordinates where the condition was True.