CertGrid CertGrid
Concepts·Certified Entry-Level Python Programmer

Python while and for Loops

Objective 2.2 - perform different types of iterations - is the other half of PCEP's 29% control-flow block. Python has two loop statements and they are for different jobs: `while` tests a condition, `for` walks a sequence. Most of the questions are really about `range`, which has three argument forms, produces nothing until you iterate it, and returns an empty sequence rather than an error when the arguments make no sense.

Control Flow Guide 11 of 26 Beginner

Written against the versions above. `range` has been a lazy object rather than a list since Python 3.0 - that is one of the defining Python 3 changes. Material showing `range(3)` printing as `[0, 1, 2]` is Python 2 and should be discarded.

One machine, and any shell with Python 3 will do - these exams test the language, not a distribution.
Server NameIP AddressOSRolesCPURAMHDD
RUNNER01192.168.0.27Ubuntu 26.04 LTSPython 3.14.4 - the only machine this path needs2 Core4 GB50 GB

Before you start

  1. while: test, run, repeat

    A while loop tests its condition before every iteration, including the first. If the condition is true it runs the block and tests again.

    Nothing changes the condition for you. If the body does not move the loop towards falsity, it never ends.

    bash Example session
    cat > ~/py/whilebasic.py <<'PY'n = 0while n < 3:    print("n is", n)    n += 1print("loop finished with n =", n)PYpython3 ~/py/whilebasic.pyn is 0n is 1n is 2loop finished with n = 3

    Expected resultn is 0, 1, 2, then loop finished with n = 3.

    Success conditionYou can trace a while and say what the counter is when it stops.

  2. A while whose body never runs

    Because the test comes first, a while can execute zero times. There is no do-while in Python - no form that guarantees one pass.

    bash Example session
    cat > ~/py/whilenever.py <<'PY'n = 10while n < 3:    print("this body never runs")print("condition was false before the first iteration")PYpython3 ~/py/whilenever.pycondition was false before the first iteration

    Expected resultOnly the message after the loop.

    Success conditionYou know a while body is not guaranteed to run at all.

  3. for: walk something, one item at a time

    for does not count. It takes each item of an iterable in turn and binds it to the loop variable. Strings, lists, tuples, dictionaries, sets and range objects are all iterable.

    Four loops below, over four different types.

    bash Example session
    cat > ~/py/forover.py <<'PY'for ch in "abc":    print("char:", ch) for item in [10, 20]:    print("list item:", item) for item in (1, 2):    print("tuple item:", item) for key in {"a": 1, "b": 2}:    print("dict key:", key)PYpython3 ~/py/forover.pychar: achar: bchar: clist item: 10list item: 20tuple item: 1tuple item: 2dict key: adict key: b

    Expected resultThree characters, two list items, two tuple items, then two dictionary keys.

    Success conditionYou can loop over any of the four collection types.

  4. range, in all three forms

    range is where most of the loop questions actually live. It takes one, two or three arguments:

    | Call | Means | |---|---| | range(stop) | 0 up to but not including stop | | range(start, stop) | start up to but not including stop | | range(start, stop, step) | as above, in steps of step, which may be negative |

    list() is wrapped around each one below only so you can see the contents - the last line shows what range really is.

    bash Example session
    cat > ~/py/ranges.py <<'PY'print("range(5)        ", list(range(5)))print("range(2, 5)     ", list(range(2, 5)))print("range(2, 11, 3) ", list(range(2, 11, 3)))print("range(5, 0, -1) ", list(range(5, 0, -1)))print("range(5, 0)     ", list(range(5, 0)))print("range(0)        ", list(range(0)))print("range(5) itself ", range(5), type(range(5)).__name__, "len", len(range(5)))PYpython3 ~/py/ranges.pyrange(5)         [0, 1, 2, 3, 4]range(2, 5)      [2, 3, 4]range(2, 11, 3)  [2, 5, 8]range(5, 0, -1)  [5, 4, 3, 2, 1]range(5, 0)      []range(0)         []range(5) itself  range(0, 5) range len 5

    Expected result[0, 1, 2, 3, 4], [2, 3, 4], [2, 5, 8], [5, 4, 3, 2, 1], then two empty lists, then range(0, 5) range len 5.

    Success conditionYou can produce any sequence the objective asks for, forwards or backwards.

  5. The two ways range refuses

    Only two argument combinations actually raise, and they raise different exceptions.

    bash Example session
    python3 -c 'print(list(range(1, 10, 0)))'Traceback (most recent call last):  File "<string>", line 1, in <module>    print(list(range(1, 10, 0)))               ~~~~~^^^^^^^^^^ValueError: range() arg 3 must not be zero[exit 1]python3 -c 'print(list(range(1.5)))'Traceback (most recent call last):  File "<string>", line 1, in <module>    print(list(range(1.5)))               ~~~~~^^^^^TypeError: 'float' object cannot be interpreted as an integer[exit 1]

    Expected resultValueError: range() arg 3 must not be zero, then TypeError: 'float' object cannot be interpreted as an integer.

    Success conditionYou can name both exceptions and say which argument caused each.

  6. The loop variable outlives the loop

    A for loop does not create a scope. The loop variable is an ordinary variable in the enclosing scope, and it keeps its last value after the loop ends.

    If the loop never ran, it was never assigned - and asking for it then does what asking for any unassigned name does.

    bash Example session
    cat > ~/py/loopvar.py <<'PY'for i in range(3):    passprint("i is still", i) for j in []:    passprint("j is", j)PYpython3 ~/py/loopvar.pyi is still 2Traceback (most recent call last):  File "/home/sysadmin/py/loopvar.py", line 7, in <module>    print("j is", j)                  ^NameError: name 'j' is not defined[exit 1]

    Expected resulti is still 2, then a NameError for j.

    Success conditionYou can say what a loop variable holds after the loop, including when it holds nothing.

  7. Nested loops

    A loop can contain a loop. The inner one runs completely on every iteration of the outer one, so the total number of body executions is the product.

    Three outer iterations, two inner each: six lines of output, arranged into three rows by the print() at the outer level.

    bash Example session
    cat > ~/py/nestedloops.py <<'PY'for i in range(3):    for j in range(2):        print(i, j, end="   ")    print()PYpython3 ~/py/nestedloops.py0 0   0 11 0   1 12 0   2 1

    Expected resultThree rows, each holding two pairs.

    Success conditionYou can count the iterations of a nested loop.

  8. What the exam does with this objective

    Objective 2.2 covers both loops and their control statements, so it carries most of block 2's 29%. From this half of it:

    "How many times does this loop run?" - range excludes its stop value.

    "What does range(5, 0) produce?" - an empty sequence, not an error.

    "What is i after the loop?" - the last value for a for, one past the last for a while.

    "What does iterating a dictionary give you?" - the keys.

    "What does range(3) print?" - range(0, 3), not a list.

    "What exception does range(1.5) raise?" - TypeError.

    The technique that pays for itself is writing out the loop variable's value for each iteration in the margin. Every off-by-one question collapses once the sequence is written down.

    guide 12 finishes block 2.

    bash
    rm -f ~/py/whilebasic.py ~/py/whilenever.py ~/py/forover.py ~/py/ranges.py ~/py/loopvar.py ~/py/nestedloops.py && ls -A ~/py

    Expected resultAn empty scratch directory.

    Success conditionYou can predict the iteration count and the final variable value for either loop.

Troubleshooting

Official sources