1 of 7
Read the loop before you delete it
Four questions about the index, and the loop names the pattern that replaces it.
The first lesson of this module said why a Python loop over an array is slow, and it is worth restating because it is the whole motivation. Every iteration is an interpreter step: follow a pointer to an object, ask that object what addition means, allocate a result, store it. The numbers are sitting in one contiguous block and nothing is walking that block -- the interpreter is walking a list of instructions instead.
Deleting the loop is not a micro-optimization. It is writing down what the operation is, once, so that a compiled routine can walk the block. The expression is usually shorter than the loop too, and that turns out to be the smaller benefit.
But you cannot delete a loop you have not read. Four questions, in this order, and between them they name the pattern:
- What does the index touch? If
iappears only asa[i]andout[i]-- the same position on both sides -- then nothing crosses between elements. Pattern one. - Is there an accumulator? A variable set before the loop and updated inside it is a reduction, and the loop it lives in is the axis. Pattern two.
- Is there an
if? A condition asked one element at a time is a mask over all of them. Pattern three. - Is the loop nested? If the two indices reach into different arrays, one operand repeats and that is broadcasting, pattern four. If both indices reach into both arrays and the innermost loop accumulates, the shared index is summed away, and that is a matrix multiply, pattern five.
Most real loops are two or three of those stacked. Read from the inside out and name each one as you meet it.
The habit that makes this safe: keep the loop. Write the expression beside it, run both on a small array, and compare before you delete anything. That is not advice about this page, it is what this page does -- every board below runs its loop and its expression when the server starts, and a pattern that disagrees with its own loop never reaches you.