Skip to content

Flow control

This page covers the statements that decide which code runs and how often: if, elif and else; while and for loops with their else clauses; break and continue; comparisons chained together; and, or and not; the one-line conditional expression; and assert. d/Python implements all of it. The compiler generates code tailored to each block, and the tests check evaluation order, short-circuiting and side effects against the reference CPython build (3.9.6) that every d/Python test is compared with.

Branches

for n in range(1, 16):
    if n % 15 == 0:
        print("FizzBuzz")
    elif n % 3 == 0:
        print("Fizz")
    elif n % 5 == 0:
        print("Buzz")
    else:
        print(n)

Loops, with their else

count = 0
while True:
    count += 1
    if count == 3:
        break
else:
    print("never printed: the loop broke")
print("count", count)

for n in range(3):
    pass
else:
    print("the for loop finished without break")

for letter in "abc":
    if letter == "b":
        continue
    print(letter, end=" ")
print()

for can loop over a range, a list, a tuple, a string, a bytes value, a dictionary or one of its views, a set, and any of the lazy iterators d/Python supports. The else clause of a loop runs when the loop ended on its own rather than through break.

Comparisons and logic

a, b, c = 1, 2, 3
print(a < b < c, a < b > c, 1 == True, 0 == False)
print(True and True, 0 or 5, not [], not "x", None is None)
def loud(value):
    print("evaluating", value)
    return value
print(loud(0) and loud(1), loud(2) or loud(3))

A chain such as a < b < c evaluates each value once, as in Python. and and or stop as soon as the answer is known and return one of their operands rather than a plain True or False; the loud function above shows which calls actually happen. One limit today: both sides of and or or must have the same type. [] or "fallback" mixes a list and a string, so the compiler stops there and says the result would have mixed types.

Conditional expressions

moves = 9
message = "A draw!" if moves == 9 else "Keep playing"
print(message, "even" if moves % 2 == 0 else "odd")

The two branches must produce the same kind of value, because the compiler generates code for one result type.

Assertions

assert 1 + 1 == 2
try:
    assert 2 + 2 == 5, "arithmetic has failed"
except AssertionError as error:
    print("AssertionError:", error)

Cleanup through control flow

Leaving a try/finally block or a with block early with return, break or continue still runs the cleanup, in the order Python defines; see Exceptions & Context Managers. A function may call itself up to 128 levels deep, and going past that raises an error you can catch; see Functions & Closures.

What the tests cover

Every claim on this page comes from a test program that runs in both d/Python and CPython and must print the same thing. The corpus page lists those programs, with their reviewed output.