Nested For Loops โ€” Star Pattern Printing

A loop inside a loop, traced step by step with Python Tutor โ€” outer loop controls rows, inner loop controls stars per row.

Overview

This topic covers nested for loops in Python, using the classic example of printing a right-angled triangle made of stars (*). It combines two learning tools:

  1. Python Tutor (pythontutor.com) โ€” used to visualize, step-by-step, how the outer and inner loop variables change and how output is built line by line.
  2. Jupyter Notebook โ€” used to run the actual code and make it dynamic by accepting the number of rows from user input.

The goal is to understand how a nested loop executes internally (which is often the confusing part), not just what code to write.

Key Concepts

The Core Code

for i in range(1, 6):
    for j in range(0, i):
        print("*", end=" ")
    print("")

Line-by-line explanation

LineWhat it does
for i in range(1, 6):Outer loop โ€” runs i from 1 to 5 (5 rows total, since range(1,6) excludes 6).
for j in range(0, i):Inner loop โ€” runs j from 0 up to i-1, so it loops i times for each row.
print("*", end=" ")Prints a star and a space, staying on the same line (end=" " overrides the default newline).
print("")After the inner loop completes, this moves to a new line to start the next row.

Expected Output:

*
* *
* * *
* * * *
* * * * *
Note: Row i prints exactly i stars โ€” this is the key relationship to remember for any triangle-pattern problem.

Tracing Execution with Python Tutor

Python Tutor was used to visualize the code execution step by step. This is very useful for understanding how variable values change over time in a nested loop.

How it works

Step-by-step trace observed in the screenshots

StepLine executingijOutput so far
1for i in range(1,6): (about to start)โ€”โ€”(empty)
2for i in range(1,6): just executed โ†’ next is for j in range(0,i)1โ€”(empty)
3for j in range(0,i): executing10 (about to be assigned)(empty)
...inner loop runs, printing stars10*
... (many steps)outer and inner loops continueincreasingincreasingbuilding up triangle
46 (final)Done running54Full triangle: * / * * / * * * / * * * * / * * * * *

Key observations from the trace:

๐Ÿ’ก Tip: If a nested loop pattern is confusing, paste the code into Python Tutor and step through it line-by-line. Watching the variable values update alongside the output makes the logic click much faster than just reading the code.

Making It Dynamic โ€” Taking User Input

Instead of hardcoding range(1, 6), the number of rows can be taken from the user so the pattern size becomes flexible.

rows = int(input("Enter the number of rows"))

for i in range(1, rows + 1):
    for j in range(0, i):
        print("*", end=" ")
    print("")

Explanation of changes

Example Run (Jupyter Notebook)

Input:

Enter the number of rows: 10

Output:

*
* *
* * *
* * * *
* * * * *
* * * * * *
* * * * * * *
* * * * * * * *
* * * * * * * * *
* * * * * * * * * *
Note: This confirms the pattern rule holds for any input โ€” row i always has exactly i stars, up to rows.

Practice Reference (from notebook comments)

Before writing the loop, the pattern to build was sketched out as a comment for planning:

# *
# **
# ***
# ****
# *****

This is a useful habit โ€” sketch the expected output first (as comments), then reverse engineer the loop logic (rows vs. stars-per-row) from that shape.

Things to Remember

Quick Revision

To print a triangle of stars with n rows:

rows = int(input("Enter the number of rows"))
for i in range(1, rows + 1):      # controls row number / stars in that row
    for j in range(0, i):         # runs i times for row i
        print("*", end=" ")       # stay on same line
    print("")                     # move to next line after row is done