5.2 Loops

Loops are control structures that allow us to execute a block of code repeatedly. Each execution is called an iteration. For example, when you count from 1 to 10, you are iterating over the numbers from 1 to 10.

Code within loops can be executed either a specific number of times (definite loop) or until a certain condition is met (indefinite loop).

In Python, there are two main loop structures:

Most of these structures can be used interchangeably, but each has its own use case.

5.2.1 Elements of a loop

Loops consist of three main elements:

  • Initialization. Set the initial value of the iteration variable. For example, i = 1, count = 0, etc.
  • Stop Condition. Define the condition that stops the loop. For example, i <= 10, count < 5, etc.
  • Increment/Decrement. Update the iteration variable to move to the next iteration. For example, i += 1, count += 1, etc.
WarningWhat Is Happening Inside the Loop?

Loops add complexity to the program control flow. To better understand the execution sequence:

  • Track your code line by line using a debugger.
  • Check what each variable holds during execution.

5.2.2 Common applications of loops

In the following, we will cover different applications of loops in Python. Consider coming back to these examples after learning the details of each loop structure.

Iterating over lists or collections

Loops allow you to process each element in a list or collection. For example:

  • Processing each element in a list.
  • Iterating over a range of numbers.

Select Run Code to execute each live example in your browser. Change the list, loop bounds, or condition, then run the code again and trace what changes.

Listing 1: Iterating over a list of numbers and printing each number.

Looping through a list

You can iterate over the elements of a list using a for loop. In each iteration, the loop variable takes the value of the current element in the list. In Listing 2, we have an example of looping through a list.

Listing 2: Looping through a list of fruits and printing each fruit.

In Listing 3, we have an example of looping through a list with the index of each element using the range function.

Listing 3: Looping through a list of fruits and printing the index and fruit for each element using the range function.

In Listing 4, we have an example of looping through a list with the index of each element. The enumerate function is used to get both the index and the element in each iteration.

Listing 4: Looping through a list of fruits and printing the index and fruit for each element.

If you transform the result of the enumerate function into a list, you will get a list of tuples where each tuple contains the index and the element. In Listing 5, we have an example of transforming the result of the enumerate function into a list. So, the output will be [(0, "apple"), (1, "banana"), (2, "cherry")]. Therefore, what the for loop does is to map each tuple to the variables i and fruit.

Listing 5: Transforming the result of the enumerate function into a list of tuples containing the index and the element.

If you want to loop through a list in reverse order, you can use the reversed function. In Listing 6, we have an example of looping through a list in reverse order.

Listing 6: Looping through a list of fruits in reverse order and printing each fruit.

In multidimensional lists, you can use nested loops to iterate over the elements of the inner lists. In Listing 7, we have an example of looping through a 2D list.

Listing 7: Looping through a 2D list and printing each element. The inner loop iterates over the elements of each row, and the outer loop iterates over the rows.

Calculating aggregates

Each iteration can update a variable to calculate the aggregate. For example:

  • Summing all numbers in a list.
  • Counting the number of elements satisfying a specific condition.

Listing 8 shows a loop that accumulates a total and a count.

Listing 8: Calculating and checking the count, total, and average of a list of numbers.

Data validation and input

Loops can repeatedly prompt for user input until a valid value is entered. For example:

  • Repeatedly asking for numbers within a range.
  • Repeatedly asking for the correct input format of a password or list of arguments.
def data_validation_example():
    while True: # Loop until a valid input is received
        user_input = int(input("Enter a number between 1 and 100: "))
        if 1 <= user_input <= 100:
            break # Exit the loop if the input is valid
    print("Valid Input:", user_input)

Example of data validation using a while loop. The loop will continue until the user enters a number between 1 and 100.

Searching and filtering

Loops can be used to search for specific elements in a collection. For example:

  • Finding the first occurrence of a value in a list.
  • Filtering elements that meet a specific condition.
  • Searching for the maximum or minimum value in a list.
  • Finding the index of a specific element in a list.
Listing 9: Example of finding the maximum number in a list using a loop.

Generating patterns or sequences

With loops, the same code block can be executed multiple times to generate patterns or sequences. If the sequence obeys a logic that depends on the iteration number, loops are a good choice. For example:

  • Calculating the factorial of a number (1 * 2 * 3 * ... * n).
  • Generating a sequence of prime numbers (see Listing 10).
Listing 10: Example of generating prime numbers up to 20 using a nested loop. Notice that list(range(2, 0)) and list(range(2, 1)) both return an empty list.

Repeating actions

Loops can be used to repeat actions or apply the same operation to multiple elements. For example:

  • Sending emails to a list of recipients.
  • Applying a transformation to each item in a collection.

Listing 11 shows the same action applied to each contact. The example prints messages only; it does not send email.

Listing 11: Repeating a placeholder email action for every contact in a list.

5.2.3 Looping statements

In the following sections, we will cover the different loop structures in Python. These structures allow you to repeat a block of code a specified number of times or until a certain condition is met.

TipLoops Across Programming Languages

The loop structures in Python are similar to those in other programming languages. If you learn loops in Python, you will be able to apply the same concepts in other languages like Java or C++.

5.2.4 for loop (definite)

When you know in advance how many times you want to execute a block of code, you can use a for loop. In this structure, the loop configuration, namely the initialization, stop condition, and increment, are defined in a single line, at the beginning of the loop. In Figure 1, we have the structure of a For loop. Notice that the condition is checked at the beginning of the loop. Then, the loop body is executed if the condition is True and the iteration variable is updated before checking the condition again.

graph LR
  Start((Start))-->for
  for --> LoopStart[Initialize<br>iteration variable<br>Define Stop Condition and <br>Configure Increment]
  LoopStart-->Condition{Condition}
  Condition-->|True|Statement1["`**Loop Body**
  Statement 1
  Statement 2
  ...
  Statement N`"]
  Statement1 --> ForNext["Update iteration
                          variable"]
  ForNext --> Condition
  Condition{Condition} ---->|False| End((End))
Figure 1: Structure of a for loop. The loop is configured at the beginning, with the initialization, stop condition, and increment. The condition is checked at the beginning of the loop. Then, the loop body is executed if the condition is True. If the condition is False, the loop is exited. After executing the loop body, the iteration variable is updated before checking the condition again.

In the Listing 12, the for loop prints the numbers from 1 to 5. The range() function generates a sequence of numbers from the start value (inclusive) to the end value (exclusive). The parameters of the range() function are start, stop, and step:

  • start: The starting value of the sequence (default is 0).
  • stop: The end value of the sequence (exclusive).
  • step: The increment or decrement value (default is 1).

In Table 1, we show examples of using the range() function.

Table 1: Examples of using the range() function.
Function Call Description Output
range(5) Generates numbers from 0 to 4 0, 1, 2, 3, 4
range(1, 6) Generates numbers from 1 to 5 1, 2, 3, 4, 5
range(1, 11, 2) Generates numbers from 1 to 10, incrementing by 2 1, 3, 5, 7, 9
range(5, 0, -1) Generates numbers from 5 to 1, decrementing by 1 5, 4, 3, 2, 1
Listing 12: Example of a for loop that prints the numbers from 1 to 5. The loop will run as long as i is less than 6.

The elements are as follows:

  • Initialization: i = 1. The loop variable i is initialized to 1.
  • Stop Condition: i < 6. The loop will run as long as i is less than 6.
  • Increment: i += 1. The loop variable i is incremented by 1 after each iteration.

Using step in for loop

In Python, the range() function can accept a step argument, allowing you to specify the increment or decrement value. For example, range(1, 11, 2) will generate numbers from 1 to 10, incrementing by 2, as Listing 13 shows.

Listing 13: Using a positive step to visit the odd numbers from 1 through 9.

If you want to decrement the loop variable, you can use a negative value for step, as Listing 14 shows.

Listing 14: Using a negative step to visit the numbers from 5 down to 1.

Nested loops

Nested loops are loops within loops. They are useful when you need to perform multiple iterations based on different conditions.

When using nested loops, the inner loop will complete all its iterations before the outer loop moves to the next iteration.

For example, Listing 15 makes the order of the two loops visible.

Listing 15: Showing that the inner loop completes before the outer loop advances.

5.2.5 for ... in loop

The for ... in loop is used to iterate through elements of a collection or iterable object. With the for loop, you can process each item in a collection without knowing its size in advance.

Listing 16: Example of a for ... in loop that iterates over a list of fruits. The loop will run for each element in the list and print the name of the fruit.

5.2.6 while loop (indefinite)

This loop allows us to repeat a block of code until a certain condition is met. It can be used when the number of iterations is not known in advance.

In Figure 2, we have the structure of a while loop. Notice that the condition is checked at the beginning of the loop. Then, the loop body is executed if the condition is True.

graph LR
  Start((Start)) --> LoopStart[Initialize<br>iteration variable]
  LoopStart --> While[while]
  While-->Condition{Condition}
  Condition--True-->Statement1["`**Loop Body**
  Statement 1
  Statement 2
  ...
  Statement N
  _(Update iteration variable)_`"]
  Statement1--->Condition
  Condition ---->|False| End((End))
Figure 2: Structure of a while loop. Notice that the condition is checked at the beginning of the loop. Then, the loop body is executed if the condition is True. If the condition is False, the loop is exited. Inside the loop, the iteration variable is updated before checking the condition again.

In the code example below, we have a while loop that prints the numbers from 1 to 5.

Listing 17: A while loop that prints the numbers from 1 to 5. The loop will run as long as count is less than or equal to 5. First, the iteration variable count is initialized to 1. Then, the loop body is executed while count is less than or equal to 5. The loop body prints the value of count and increments count by 1. The loop stops when count is greater than 5.

Entering the loop before checking the stop condition

Sometimes you want to ensure that the loop runs at least once. In this case, you can use a while True loop with a break statement. In Listing 17, we have a standard while loop that prints the numbers from 1 to 5. In Listing 18, we have a while True loop that prints the number 6. Notice that count starts with 6 (i.e., the stop condition is True) but the code block within the loop is executed nevertheless. This happens because the condition is checked at the end of the loop.

Figure 3 shows the corresponding control flow: the loop body is entered before the stop condition is checked.

graph LR
  Start((Start)) --> LoopStart[Initialize<br>iteration variable]
  LoopStart --> While[while True]
  While-->Statement1["`**Loop Body**
  Statement 1
  Statement 2
  ...
  Statement N
  _(Update iteration variable)_`"]
  Statement1--->Condition -->|True| While
  Condition{While<br>Condition} -->|False| End((End))
Figure 3: In a Do ... Loop While loop, the loop body is executed before checking the stop condition. This allows the loop to run at least once, even if the stop condition is already met.
Listing 18: Example of a while True loop that prints the number 6. The iteration variable count is initialized to 6. The loop body prints the value of count, increments it to 7, and then stops because count <= 5 is False. The loop body therefore executes once even though the continuation condition is false after the first update.

Checking the condition at the end is especially useful when you need to validate user input before entering the loop. For example, in the code below, the user is prompted to enter a number between 1 and 100. The loop will keep asking for input until a valid number is entered.

def validate_input():
    while True:
        user_input = int(input("Enter a number between 1 and 100: "))
        if 1 <= user_input <= 100:
            break
    return user_input

If we did not use a while True loop, we would need to duplicate the input prompt code before the loop to ensure that the loop runs at least once:

def validate_input():
    user_input = int(input("Enter a number between 1 and 100: "))
    while not 1 <= user_input <= 100:
        user_input = int(input("Enter a number between 1 and 100: "))
    return user_input

5.2.7 continue statement

Sometimes you need to skip part of the code in a loop and continue to the next iteration. The continue statement:

  • ends the current iteration in a loop, and
  • continues to the next iteration.

Using continue, you can skip code for certain iterations. In Listing 19, iterations 2 and 4 skip the final print statement.

Listing 19: Skipping selected iterations in a for loop with continue.

We can also use continue in a while loop. In Listing 20, the loop skips the number 3.

Listing 20: Skipping one iteration in a while loop with continue.

5.2.8 break statement

Sometimes you need to exit a loop before it completes all iterations. To prematurely exit loops when a condition is met, you can use the break statement.

In Listing 21, we have a for loop that will break when i is equal to 5. In Listing 22, we have a while True loop that will break when count is greater than 5.

Listing 21: Example of a for loop that ends prematurely. The loop is supposed to run from 1 to 10, but it stops when i is equal to 5. The loop prints the numbers from 1 to 4 and then prints "Finished execution."
Listing 22: Example of a while True loop that ends prematurely. The loop is supposed to run indefinitely, but it stops when count is greater than 5. The loop prints the numbers from 1 to 5 and then prints "Finished program."

Loops and list comprehension

List comprehension is a concise way to create lists in Python. It allows you to create a new list by applying an expression to each element of an existing list. In Table 2, we have examples of list comprehension.

Table 2: Examples of list comprehension in Python.
List Comprehension Description Example Result
[expression for item in list] Applies the expression to each item in the list. [x*2 for x in [1, 2, 3]] [2, 4, 6]
[expression for item in list if condition] Applies the expression to each item in the list that satisfies the condition. [x*2 for x in [1, 2, 3] if x > 1] [4, 6]
[expression if condition else other for item in list] Applies the expression to each item in the list if the condition is True, otherwise applies other. [x*2 if x > 1 else x for x in [1, 2, 3]] [1, 4, 6]

Why use list comprehension?

The main advantages of using list comprehension are:

  • Concise Syntax: List comprehension allows you to create lists in a single line of code, making it more concise and readable.
  • Efficient: List comprehension is more efficient than traditional for loops as it reduces the number of lines of code and improves performance. The performance improvement comes from the fact that list comprehension is optimized for speed (it is implemented in C under the hood).
  • Functional Programming: List comprehension is a functional programming concept that emphasizes the use of expressions and functions to create lists, making your code more functional and declarative. So far, you have been using imperative programming, which focuses on statements and loops to achieve a result.
  • Operations: List comprehensions can filter, map, and transform list values.
  • Pythonic: List comprehension is a common practice in Python and is considered Pythonic, meaning it follows the idiomatic style and conventions of the Python language.

About the speed-up factor, Listing 23 provides an example of how list comprehension can be faster than traditional for loops.

Listing 23: Comparing the runtime of creating a list of squared numbers using a traditional for loop and list comprehension. The runtime is given in seconds. Using list comprehension is 1.26 times faster than using a for loop. The difference in runtime becomes more significant as the size of the list increases. The time module is used to measure the runtime (in seconds) of each operation.
(a) Version with for loop.
import time
start_time = time.time()
squared = []
for i in range(10_000_000):
    squared.append(i ** 2)
runtime_for = time.time() - start_time
print("Runtime:", runtime_for)
Runtime: 1.6248464584350586
(b) Version with list comprehension.
import time
start_time = time.time()
squared = [i ** 2 for i in range(10_000_000)]
runtime_lc = time.time() - start_time
print("Runtime:", runtime_lc)
Runtime: 1.2933697700500488

In examples Listing 24, Listing 25, Listing 26, and Listing 27, we have examples of list comprehension compared to traditional for loops.

Listing 24: Applying the expression n ** 2 to each element n in the list numbers using a traditional for loop and list comprehension.
(a) Version with for loop.
(b) Version with list comprehension.
Listing 25: Filtering elements that are even using a traditional for loop and list comprehension.
(a) Version with for loop.
(b) Version with list comprehension.
Listing 26: Apply the expression n ** 2 to even elements and n to odd elements using a traditional for loop and list comprehension.
(a) Version with for loop.
(b) Version with list comprehension.
Listing 27: Flattening a 2D list using a traditional for loop and list comprehension. Flattening means converting a multidimensional list into a one-dimensional list.
(a) Version with for loop.
(b) Version with list comprehension.

5.2.9 Exercises

5.2.Q1 Cumulative sum of numbers

Write a function named cumulative_sum_numbers that takes an integer n as input and returns the sum of all integers from 1 to n, inclusive. Use a for loop.

If n is less than 1, the range contains no integers and the returned sum is 0.

Complete the supplied function in Listing 28. Keep its signature and use the checks below it.

Listing 28: Starter function and supplied checks for cumulative sum of numbers.

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false.

5.2.Q2 Average of numbers

Write a function named average_numbers that takes a positive integer n as input and returns the average of all integers from 1 to n, inclusive. Use a for loop.

Complete the supplied function in Listing 29. Keep its signature and use the checks below it.

Listing 29: Starter function and supplied checks for average of numbers.

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false.

5.2.Q3 Sum of odd numbers

Write a function named sum_odd_numbers that takes an integer n as input and returns the sum of all odd integers from 1 to n, inclusive. Use a for loop.

If n is less than 1, the range contains no integers and the returned sum is 0.

Complete the supplied function in Listing 30. Keep its signature and use the checks below it.

Listing 30: Starter function and supplied checks for sum of odd numbers.

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false. The % operator gives the remainder after division; 7 % 2 is 1.

5.2.Q4 Factorial of a number

Write a function named factorial that takes a non-negative integer n as input and returns the factorial of n. Use a for loop.

The factorial is the product of integers from 1 through n. By definition, 0! is 1.

Complete the supplied function in Listing 31. Keep its signature and use the checks below it.

Listing 31: Starter function and supplied checks for factorial of a number.

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false.

5.2.Q5 Calculate the power of a number

Write a function named power that takes a number x and an integer exponent y as input and returns x raised to the power of y. Use a for loop rather than ** or pow. Remember that a negative exponent requires the reciprocal of the corresponding positive power.

Use finite numeric inputs. If x is 0, use a nonnegative exponent. For this exercise, exponent 0 returns 1, including when x is 0.

Complete the supplied function in Listing 32. Keep its signature and use the checks below it.

Listing 32: Starter function and supplied checks for calculate the power of a number.

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false. abs(value) returns its magnitude, so abs(-2) is 2. math.isclose(a, b) checks whether 2 numeric values are close within its tolerances; isclose(0.1 + 0.2, 0.3) is True with the default tolerances.

range(stop) supplies integers from 0 up to, but excluding, stop; list(range(3)) is [0, 1, 2].

5.2.Q6 Check prime number

Write a function named is_prime that takes an integer n as input and returns True if n is a prime number; otherwise, return False. Use a for loop.

A prime number is an integer greater than 1 whose only positive divisors are 1 and itself.

Complete the supplied function in Listing 33. Keep its signature and use the checks below it.

Listing 33: Starter function and supplied checks for check prime number.

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false. The % operator gives the remainder after division; 6 % 3 is 0.

5.2.Q7 Reverse a string

Write a function named reverse_string that takes a string text as input and returns a new string with the characters of text reversed. Use a for loop rather than slicing with [::-1].

Complete the supplied function in Listing 34. Keep its signature and use the checks below it.

Listing 34: Starter function and supplied checks for reverse a string.

len(text) returns the number of characters, so len("cat") is 3 and len("") is 0. A for loop over a string visits its characters in order. String indexing starts at 0, so "cat"[0] is "c"; the index must refer to an existing character.

assert condition stops the check with an AssertionError when the condition is false.

5.2.Q8 Remove spaces from a string

Write a function named remove_spaces that takes a string text as input and returns a new string with all space characters (" ") removed. Use a for loop.

Remove only the ordinary space character (" "). Preserve tabs, newlines, and all other characters.

Complete the supplied function in Listing 35. Keep its signature and use the checks below it.

Listing 35: Starter function and supplied checks for remove spaces from a string.

len(text) returns the number of characters, so len("cat") is 3 and len("") is 0. A for loop over a string visits its characters in order. String indexing starts at 0, so "cat"[0] is "c"; the index must refer to an existing character.

assert condition stops the check with an AssertionError when the condition is false.

5.2.Q9 Count vowels in a string

Write a function named count_vowels that takes a string text as input and returns the number of vowels (A, E, I, O, U) in the string. Count both uppercase and lowercase vowels, and use a for loop.

Complete the supplied function in Listing 36. Keep its signature and use the checks below it.

Listing 36: Starter function and supplied checks for count vowels in a string.

len(text) returns the number of characters, so len("cat") is 3 and len("") is 0. A for loop over a string visits its characters in order. String indexing starts at 0, so "cat"[0] is "c"; the index must refer to an existing character.

assert condition stops the check with an AssertionError when the condition is false. character in text checks membership; "a" in "cat" is True.

5.2.Q10 Scan a password in one pass

Write check_password using one for loop over the password. Return "Valid" only when all five rules are satisfied:

  1. at least one uppercase letter;
  2. at least one lowercase letter;
  3. at least one digit;
  4. at least one character from SPECIAL_CHARACTERS; and
  5. at least eight characters in total.

Return "Invalid" when any rule is unsatisfied. Use the special-character string supplied in the listing. This exercise checks the stated rules only.

Complete the supplied function in Listing 37. Keep its signature and use the checks below it.

Listing 37: Starter function and supplied checks for one-pass password validation.

len(text) returns the number of characters, so len("cat") is 3 and len("") is 0. A for loop over a string visits its characters in order. String indexing starts at 0, so "cat"[0] is "c"; the index must refer to an existing character.

assert condition stops the check with an AssertionError when the condition is false. character.isupper(), character.islower(), and character.isdigit() return Boolean character classifications. For a single character, "A".isupper(), "a".islower(), and "7".isdigit() are True; "!".isdigit() is False. character in SPECIAL_CHARACTERS checks whether that character belongs to the supplied string.

5.2.Q11 Validate a password with helper functions

Build a modular password validator. Implement the 4 character helpers below with their own loops, then let validate_password combine their Boolean results. This is a standalone decomposition exercise; all rules and interfaces are defined here.

The password is valid when it contains an uppercase letter, a lowercase letter, a digit, a character from SPECIAL_CHARACTERS, and at least eight characters.

The 4 character helpers return True when their named character type is present and False otherwise. The supplied has_minimum_length(password, minimum=8) returns whether the length is at least minimum; use a nonnegative minimum. validate_password returns "Valid" when all rules are met and "Invalid" otherwise. The supplied length helper is already implemented; write a loop in each character helper.

Complete the supplied functions in Listing 38. Keep their signatures and use the checks below them.

Listing 38: Starter functions and supplied checks for password validation with helper functions.

Test each helper separately before testing the combined validator.

len(text) returns the number of characters, so len("cat") is 3 and len("") is 0. A for loop over a string visits its characters in order. String indexing starts at 0, so "cat"[0] is "c"; the index must refer to an existing character.

assert condition stops the check with an AssertionError when the condition is false. "A".isupper(), "a".islower(), and "7".isdigit() are True. These methods return Boolean character classifications; "!".isdigit() is False. character in SPECIAL_CHARACTERS checks membership in the supplied string. has_minimum_length("abc", 3) returns True; has_minimum_length("abc") returns False.

5.2.Q12 Print a triangle pattern

Write a function named print_triangle_pattern that takes these inputs:

  • integer n: the height of the triangle;
  • string side: either "left" or "right".

The function must print a triangle pattern of n lines made of asterisks (*), aligned to the requested side. Use for loops.

Use a nonnegative height. Print 1 asterisk on the first line, 2 on the next, and continue through n. Right alignment uses leading spaces so every row ends in the same column. The function returns None.

Complete the supplied function in Listing 39. Keep its signature and use the checks below it.

Listing 39: Starter function and supplied checks for print a triangle pattern.
def print_triangle_pattern(n: int, side: str) -> None:
    # Add code here!
    pass


print_triangle_pattern(4, "left")

Listing 40 shows the expected printed result.

Listing 40: Expected output of the supplied example for print a triangle pattern.
*
**
***
****

Run the additional example in Listing 41.

Listing 41: Additional supplied example call for print a triangle pattern.
print_triangle_pattern(4, "right")

Listing 42 shows the expected printed result.

Listing 42: Expected output of the supplied example for print a triangle pattern.
   *
  **
 ***
****

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false. print(text) displays the supplied string followed by a newline; print("**") prints a row of 2 asterisks.

range(stop) supplies integers from 0 up to, but excluding, stop; list(range(3)) is [0, 1, 2].

5.2.Q13 Print an X pattern

Write a function named print_x_pattern that takes an integer n as input and prints an X pattern of asterisks (*). Use nested for loops.

Use a nonnegative size. The pattern has n rows and n columns before removing trailing spaces. Place asterisks on both diagonals and spaces elsewhere. For n = 0, print no lines. The function returns None.

Complete the supplied function in Listing 43. Keep its signature and use the checks below it.

Listing 43: Starter function and supplied checks for print an X pattern.
def print_x_pattern(n: int) -> None:
    # Add code here!
    pass


print_x_pattern(5)

Listing 44 shows the expected printed result.

Listing 44: Expected output of the supplied example for print an X pattern.
*   *
 * *
  *
 * *
*   *

range(start, stop) supplies integers beginning at start and ending before stop. For example, list(range(1, 4)) is [1, 2, 3]. An empty range supplies no values.

assert condition stops the check with an AssertionError when the condition is false. print(text) displays a row followed by a newline. text.rstrip() returns a new string with trailing whitespace removed; "* ".rstrip() is "*".

range(stop) supplies integers from 0 up to, but excluding, stop; list(range(3)) is [0, 1, 2].

5.2.Q14 Find the largest digit in a number

Write a function named largest_digit that takes an integer n as input and returns the largest digit in n. Use a while loop. Your function should also work for negative integers by considering the digits of abs(n).

Complete the supplied function in Listing 45. Keep its signature and use the checks below it.

Listing 45: Starter function and supplied checks for find the largest digit in a number.

abs(value) returns its magnitude, so abs(-42) is 42. % gives a division remainder, and // gives the floor of a quotient. For example, 42 % 10 is 2 and 42 // 10 is 4.

assert condition stops a failed check with an AssertionError.

5.2.Q15 Search with a post-test loop

Implement first_multiple_after with while True and break. Starting from start, increment the candidate before testing it. Stop at the first larger integer divisible by divisor. Because the test follows the increment, the loop body always runs at least once.

Both inputs are integers. A negative divisor is allowed. Preserve the supplied ValueError for a zero divisor; division by zero is undefined.

Complete the supplied function in Listing 46. Keep its signature and use the checks below it.

Listing 46: Starter function and supplied checks for search with a post-test loop.

while True repeats until a break exits the loop. % gives a remainder; 12 % 4 is 0. A ValueError reports an invalid argument value.

assert condition stops a failed check with an AssertionError.

5.2.Q17 Find the maximum value in a list

Scenario. A procedure must find the largest numeric value in a list by inspecting each element.

Inputs. A non-empty finite list L of numbers. List positions start at 0. An empty list is invalid for this procedure.

Rules and notation. Output a value from the list that is greater than or equal to every element. length(L) is the number of elements.

Assumptions. Numeric comparisons are defined for every pair of elements. The list is not changed.

Listing 48 makes the structure for find the maximum value in a list explicit so you can identify its required fields and boundaries.

Listing 48: Structured example of find the maximum value in a list.
IF length(L) = 0
    OUTPUT Invalid input
    STOP
END IF

SET largest TO L[0]
SET i TO 1

WHILE i < length(L)
    IF L[i] > largest
        SET largest TO L[i]
    END IF
    SET i TO i + 1
END WHILE

OUTPUT largest

Deliverable. Trace largest and i for L = [-4, -2, -9]. Explain why initializing largest to 0 would be defective. Give expected outputs for [-4, -2, -9], [6], [3, 3], and [].

Success criteria. The trace outputs the largest element of the list, the initialization works for all-negative lists, a one-element list returns its element without entering the loop, and empty input follows the stated invalid policy.

Initialize from a real element so that largest is always the largest value among the elements inspected so far.

5.2.Q18 Trace an iterative even sum

Scenario. A procedure adds all even whole numbers from 1 through a supplied upper bound, including the bound when it is even.

Inputs. number, a non-negative whole number. Other values are invalid.

Rules and notation. A number is even when division by 2 leaves remainder 0. For number = 0, the range is empty and the sum is 0.

Assumptions. Arithmetic does not overflow for the supplied input.

Listing 49 makes the structure for trace an iterative even sum explicit so you can identify its required fields and boundaries.

Listing 49: Structured example of trace an iterative even sum.
IF number is not a non-negative whole number
    OUTPUT Invalid input
    STOP
END IF

SET total TO 0
SET i TO 1

WHILE i <= number
    IF i is even
        SET total TO total + i
    END IF
    SET i TO i + 1
END WHILE

OUTPUT total

Deliverable. Trace i and total for number = 4. Give expected outputs for 0, 1, 2, and 4, and state why the loop terminates.

Success criteria. The trace includes the boundary value 4, adds only the even values in the range, returns 0 for an empty range, and identifies a progress measure that decreases on every iteration.

Record total after the possible addition and then increase i, even when i is odd.

5.2.Q19 Trace Algorithm X

Scenario. Algorithm X calculates a Fibonacci number. In this exercise, the sequence is defined by F(0) = 0, F(1) = 1, and F(n) = F(n - 1) + F(n - 2) for n >= 2.

Inputs. number, a non-negative whole number. Other values are invalid.

Rules and notation. The procedure must output F(number) under the supplied definition.

Assumptions. Arithmetic can represent the result for the supplied input.

Listing 50 makes the structure for trace algorithm x explicit so you can identify its required fields and boundaries.

Listing 50: Structured example of trace algorithm x.
IF number is not a non-negative whole number
    OUTPUT Invalid input
ELSE IF number <= 1
    OUTPUT number
ELSE
    SET a TO 0
    SET b TO 1
    SET i TO 2

    WHILE i <= number
        SET next TO a + b
        SET a TO b
        SET b TO next
        SET i TO i + 1
    END WHILE

    OUTPUT b
END IF

Deliverable. Trace a, b, next, and i for number = 6. Give expected outputs for 0, 1, 2, and 6. Explain what a and b represent after each completed iteration.

Success criteria. The output for 6 is F(6) under the supplied definition, both base cases avoid the loop, the first iteration produces F(2), and the stated meaning of the variables agrees with every trace row.

After the iteration labeled i, b contains F(i) and a contains F(i - 1).