Iteration using while in Python (Part 1)

Translating from pseudocode to Python

Translating pseudocode into Python follows the now-familiar pattern. We add a colon to the end of the first line of the loop that contains the keyword while and the condition. Then we indent all subsequent lines that are part of the body of the loop.

Pseudocode

while condition action

Indent

Python

while condition:
    action

Indent evenly


Python convention

Indent four spaces.


Example: saying “uncle”

As a not-at-all useful example, suppose we want to get the user to say “uncle”. In case you're not familiar with the phrase, it is supposed to be a way of getting someone to admit weakness. Here we're just planning on being annoying.

While loop recipe

  • Express the task as iteration.
  • Write a condition.
  • Ensure initial values of variables checked in the condition.
  • Ensure the condition can change in the body of the loop.

To express this idea as iteration, we use language similar to what we've seen before, that is, we “keep doing” something until something else happens. We want to keep going as long as the response is not “uncle”, which suggests a condition that is true when the response is not uncle, giving the following condition:

response != 'uncle'

In these examples I'm going to concentrate on the code fragments that we need. They are appearing in the order we are discussing them. Later, we'll put the pieces together in the right order.

We have to make sure that the parameter response has a set value before the loop is entered — that is, a value that is not 'uncle' — or we'll never enter the loop.

To change the condition, we ask for a response inside the body of the loop:

response = input("I'll quit if you say 'uncle': ")

Putting it all together

def say_uncle():
    """Docstring here
    """
    response = 'aunt'
    while response != 'uncle':
        response = input("I'll quit if you say 'uncle': ")

say_uncle()

Since the function uses user input, we don't need any parameters. For the sake of space, we've omitted the docstring.

We write the condition, set the value of response before the loop starts, and change the value inside the loop.

Now we can run the program to see how it behaves. The following output appears:

I'll quit if you say 'uncle': 

An input box appears. I type no, hit enter, and the following output appears:


I'll quit if you say 'uncle': 

An input box appears. I type maybe, hit enter, and the following output appears:


I'll quit if you say 'uncle': 

An input box appears. I type uncle, hit enter, and the program terminates.


Here we are likely to be able to count on the user eventually giving up, however in general we need to watch out for infinite loops. If the computer seems to be taking a long time to respond, click on the “stop” button and then trace your code to see where an infinite loop might be occurring.

Caution

Avoid infinite loops.


Example: determining if a number greater than 1 is prime

Let's use the recipe on another example: determining if a number greater than 1 is prime.

While loop recipe

  • Express the task as iteration.
  • Write a condition.
  • Ensure initial values of variables checked in the condition.
  • Ensure the condition can change in the body of the loop.

We know that a number is not a prime if it is the multiple of any number between 2 and one less than the number itself, so we will check if it is a multiple of anything from 2 to the number minus 1.

This might not immediately sound like iteration, until we think about the iterative process of checking possible factors.

The condition should be true when the number isn't too big, that is, the last time the loop is entered is when factor is num minus 1. This gives the following condition:

factor < num

The initial value should be the smallest number we check, namely 2.

factor = 2

To make sure that the value of the condition can change, we increase the value inside the loop body.

factor = factor + 1

Putting it all together

We will make use of the helper function is-multiple, which we created earlier.

def is_multiple(number, factor):
    return number % factor == 0

def is_prime(num):
    """Determines if num is prime.

       Preconditions:
       num: int > 1
    
       Parameters:
       num: number being checked
 
       Returns: Boolean (True if prime)
    """

In our docstring, we ensure that the number is greater than one.


    factor = 2 
    while factor < num:


        factor = factor + 1

We now write our condition, ensure there is an initial value for factor, and make sure that factor can change in the loop. Now what? Update the previous code block as follows:

    factor = 2 
    while factor < num:
        if is_multiple(num, factor):
            return False
        factor = factor + 1

If any number is a factor, we can return False, since we know that num is not a prime number.


   return True

If we get all the way through the loop without returning False, we can return True.

def test_is_prime():
    """Tests correctness of is_prime
    """
    assert is_prime(2) == True
    assert is_prime(3) == True
    assert is_prime(9) == False
    assert is_prime(50) == False
    assert is_prime(53) == True

test_is_prime()

We can use a function to check our is-prime function.

If there is no output, is-prime works correctly.


Branching inside the body of the loop in order to find a factor allowed early exit from the loop, and the entire function, due to the return statement.


Early exit using the condition

Let's look at another way to exit a loop early without using return inside the body of the loop.

def is_prime(num):
    factor = 2 
    fails = False
    while factor < num and not fails:
        fails = is_multiple(num, factor)
        factor = factor + 1
    return not fails

Here we modify the condition to allow early exit. We've added a special Boolean variable fails which flags whether or not a factor has been found. Like factor, fails needs to have a value set before the loop and it needs to have the possibility of changing in the loop. We set it to the result of is-multiple. Finally, when we exit the loop for any reason, we can return not fails as the result.