Step 1 of 7 · Reading · ~4 min
Learn
Loops and Iteration
Nested Loops and Patterns
A loop inside another loop is how you fill anything two-dimensional: a grid, a table, a board. By the end of this lesson you can say exactly how many times the innermost line runs, and you can print a block of text where each row is assembled piece by piece before it is ended.
The inner loop restarts on every outer pass
Indenting one for inside another makes the whole inner loop part of the outer loop's body. So the inner loop does not run once — it runs again from the beginning every time the outer loop takes a step.
Output:
1 1
1 2
2 1
2 2
3 1
3 2
Six lines: 3 outer passes, 2 inner passes inside each one. The counts multiply, they do not add. Unindent the inner loop and the two loops run one after the other instead: 3 lines, then 2 lines, 5 in total.
Give the two loop variables different names. Writing for i inside another for i is legal Python, but the inner loop overwrites the outer counter on every pass, and that bug is very hard to see.
Printing across instead of down
Every print call ends with a newline, which is why the example above produced one line per inner pass. To put several values on the same line, pass end="" — the text that print appends after its arguments, normally "\n", becomes nothing at all.
Output:
0120120120
Two separate things happened. Each print(..., end="") glued its character onto the current line, and the bare print() afterwards ended that line. A bare print() prints no text and one newline, and that is exactly what closes off a row.
Where the closing print goes decides the shape
The indentation of that bare print() is the entire difference between a block and a column. Put it inside the inner loop and every character ends its own line:
#
#
#
#
#
#
Move it out one level, so it lines up with the inner for and therefore runs once per outer pass:
###
###
Same six characters, different shape, and the only change is four spaces.
The inner range can depend on the outer variable
The inner range(...) is rebuilt on every outer pass, so it is allowed to use the outer loop's variable. That is how anything triangular is built:
o
oo
ooo
oooo
Level 1 prints one character, level 4 prints four, for 1 + 2 + 3 + 4 = 10 in total. Note that range(level) counts 0, 1, ... level-1, so it yields level values but never the value level itself.
Nesting multiplies the work
A loop of 1,000 steps is instant. The same loop nested inside another 1,000-step loop is a million steps, and a third level makes it a billion. Two nested loops over the same n values run n squared times, which is why a nested loop over a big input is the usual reason a program that "looks simple" takes minutes.
Common mistakes
- Omitting
end=""on the inner print: each cell gets its own newline, so an n-by-n block comes out as n squared lines of one character instead of n lines of n characters. - The bare
print()indented too far, sitting inside the inner loop: same symptom, one character per line, because the row is closed after every cell rather than after every row. - Counting from 0 when the values start at 1:
range(n)yields 0 through n-1. If the first value must be 1, you needrange(1, n + 1), or the first row and column come out as zeros and the last one is missing. - Letting a cell grow past one character: if a computed cell can reach 10 or more, rows stop lining up and become ragged. Reduce the value (for example with
% 10) so every cell is exactly one character wide.
Your exercise
Print an n-by-n grid of single digits, where each cell is computed from its own row and column number. The starter already reads n and contains the outer loop plus the print() that ends each row; you add the inner loop and the cell value. The mistake to watch for is a cell wider than one character.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…