Vectorised Arithmetic
Describing the operation instead of writing the loop - and the two habits that undo the benefit.
Overview
Operators apply to every element
a + b adds the arrays elementwise. So do -, *, /, //, % and **. A scalar applies to every element: a * 10 scales the whole array.
The one to be careful with is *. On arrays it is elementwise multiplication, not matrix multiplication. Matrix multiplication is @, and confusing the two produces an array of the wrong shape or, worse, the right shape and the wrong numbers. That has its own module later.
Comparisons work the same way and give a boolean array: a > 2 is [False, False, True, True], not a single answer. Using that in an if raises, because NumPy refuses to guess whether you meant "any" or "all".
Worth knowing
* is elementwise multiplication, not a dot product.np.sqrt apply to a whole array; math.sqrt takes one number and raises on an array.inf or nan with a warning rather than an exception. Python would have raised.a += 1 writes in place; a = a + 1 allocates a new array and rebinds the name. Aliases see one and not the other.np.where.