login
Holden Web
What you'll need to know tomorrow

Iteration: For and While Loops

We've covered a couple of basic object types in Python so far—strings and numbers. Strings are one of Python's sequence types, strings. There are other Python sequence types that can contain more than just characters. But before we tackle Python's container objects, let's take a look at how Python lets you perform the same actions repeatedly–loops.

Modern computers execute millions and even billions of instructions per second. If we had to write out every instruction the computer performed, it would take a lifetime to write less than a second's worth of code. Fortunately, we have loops at our disposal. Loops tell the computer to execute the same sequence of actions over and over. Through the use of loops we can tell the computer to repeat the same operations on different pieces of data, without repeating the same instructions each time.

At the end of the last lesson we worked with a program that contained a while loop. Using a while loop we can apply the same logic repeatedly so long as a specified condition is true. Similarly, for loops allow you to repeat the same actions on each of a sequence of objects. We'll take a closer look at for loops first.

A Basic For Loop

Suppose you wanted to count the number of vowels in a string. How would you approach this task? Traditionally, you would set a counter to zero, then loop over the characters in the string, adding one to the counter when a vowel character was found. After all the characters had been processed, the counter would contain the total number of vowels.

Let's try an example that uses a for statement to loop over the characters in a string you enter and an if statement to determine whether each character is a vowel. Put this code in a file called vowel_counter.py:

Code
"""Counts the vowels in a user input string."""

s = input("Enter any string: ")
vcount = 0
for c in s:
    if c in "aeiouAIEOU":
        vcount += 1
    print("C is ", c, "; Vowel count:", vcount)

Run it. The "Enter any string:" prompt appears. The program counts the number of vowels in any string you enter and reports a total after each character.

The for statement is followed by an indented suite (in this case, a single if statement). When the for statement executes, the name s is bound to a string. For each character in that string the interpreter executes the indented suite with the name c bound to the current character. So, suppose you entered "the". The first time through the loop, c would be "t". The second time, it would be "h", and the third time, "e". Each time around, the if statement checks whether c is a vowel. If it is, it adds 1 to the vcount counter; otherwise nothing happens because there is no else clause attached to the if. After all characters have been processed, vcount contains a count of the vowels in the input string.

We had the program print every time it went through the loop so you could see how it works. Now, let's change it to print only when it finishes reading the input string. To do that, we simply unindent the print statement so that it falls outside of the loop. We'll also remove the code that prints the value of "c":

Code
"""Counts the vowels in a user input string."""

s = input("Enter any string: ")
vcount = 0
for c in s:
    if c in "aeiouAIEOU":
        vcount += 1
    print("C is ", c, "; Vowel count:", vcount)

Save and run it again to see the difference.

Breaking Out of a Loop

The for loop is useful for processing each element in a sequence. We'll look at more complex sequences in the next lesson, but for now we'll use strings.

Suppose you wanted to know where the first space appears in a string. One way to find out would be to loop through the string, counting characters until you found a space. But once you found it, how would you stop counting? Completing the loop would be wasteful–it would be more efficient to stop looking at characters once you encountered the first space. To do that, we use the break statement. If you execute a break during a loop, the loop terminates immediately.

Let's write a program that prints the position where the first space appears in a string. Enter this code in a file called space_finder.py:

Code
"""Program to locate the first space in the input string."""

s = input("Please enter a string: ")
pos = 0
for c in s:
    if c == " ":
        break
    pos += 1
print("First space occurred at position", pos)

Run it:

Output
Please enter a string: Space, the final frontier.
First space occurred at position 6

The count (pos) starts at 0 because that's the first position of the first element in any Python sequence. Each time through the loop, we test to see if the current character (c) is a space. If it is, we break, exit the loop, and print the value from pos; otherwise we add 1 to pos and the loop continues. Be sure you get things in the right order! Incrementing the count before testing and terminating the loop would cause what's known as an "off by one error."

But what does the program do if there's no space in the input? It prints out a result as though a space followed the input string, because the loop terminates after it has inspected every character. Check it out by running the program with an input containing no spaces.

We need separate logic to verify that there really is a space in the string. Happily Python loops come with such extra logic built in, in the shape of an optional else clause. This clause is placed at the same indentation level as the for or while loop that it matches, and (just as with the if statement) is followed by an indented suite of one or more statements. This suite is only executed if the loop terminates normally. If the loop ends because a break statement is executed, the interpreter skips over the else suite. In the case of the space-detection program, we execute the break when we detect a space, so an else clause on the for loop will only run if there were no spaces in the input.

We need to modify our code a little. In the first version, the print was located at the end of the loop, where it always runs regardless of the test outcome. Now we want it to be part of the suite guarded by the if statement, so it only runs when a space is found. Modify your space_finder.py as shown:

Code
"""Program to locate the first space in the input string."""

s = input("Please enter a string: ")
pos = 0
for c in s:
    if c == " ":
        print("First space occurred at position", pos)
        break
    pos += 1
print("First space occurred at position", pos)
else:
    print("No spaces in that string")

Run it with a string that contains a space and then with a string that doesn't. You should fing the program handles both cases correctly.

As your programs become more complex you will find that there are different ways to express the same logic. In those cases, you should do the simplest thing that works. For example, in the body of the loop we could have put the statement that increments the counter in the suite of an else clause. We chose not to, because if the expression c == " " tests as true, the break statement guarantees that pos isn't incremented (by immediately exiting the loop) before the print statement is executed. This kind of attention to detail is best learned by making mistakes and correcting them. It's worth working sts, though, because understanding how you need to change something to make it work is always going to be a valuable skill.

While Loops

The for loop is useful when you want to apply the same logic to each member of a sequence. But sometimes (like in the guessing game at the end of the last lesson) you don't have a finite sequence; you want actions to be repeated as long as some condition is true.

Suppose we want to split a string into words. Defining words by the spaces between them, we can locate the first space with a for loop. We can then modify the string each time we find a word (by re-binding the name of the string to a new string with the word removed) until there are no more words left. That's the idea behind the next program. Put this in a file called sentence_splitter.py:

Code
"""Program to split a sentence into words."""

s = input("Please enter a sentence: ")
while True:

    pos = 0
    for c in s:
        if c == " ":
            print(s[:pos])
            s = s[pos+1:]
            break
        pos += 1
    else:
        print(s)
        break

Run it. The while True clause sets up a loop that will keep running until logic in the if/else suites causes a break. When you see while True in a program, either the programmer has included a break statement to terminate the loop, or the program is designed for continuous operation—or the programmer has made a terrible mistake and the program will never stop running! In this case, it's the former: the break that terminates the while loop is inside the for loop's else clause. Enter a sentence and you should see each word on a separate line.

Of course this program isn't perfect— few programs are! Try entering a sentence where the words are separated by multiple spaces. The program prints empty lines, corresponding to the "empty words" between the spaces. We can fix that. One way would be to strip leading spaces before going into the for loop each time. Let's modify sentence_splitter.py to handle multiple spaces between words:

Code
"""Program to split a sentence into words."""

s = input("Please enter a sentence: ")
while True:
    while s.startswith(" "):
        s = s[1:]

    pos = 0
    for c in s:
        if c == " ":
            print(s[:pos])
            s = s[pos+1:]
            break
        pos += 1
    else:
        print(s)
        break

Run it. You can now enter as many spaces as you like between the words and still get one word per line in the output. Can you figure out how you might use or to ignore extra tabs between words? What part of the program would you need to change to treat tabs as completely equivalent to spaces? (Hint: you would have to accept sentences with just tabs between the words.)

Modern Python The manual word-splitting above is a good exercise in loop control flow, but the standard library does this in one call: "Hello world".split() returns ['Hello', 'world'], handling any mix of spaces and tabs. We'll see that at the end of this lesson.
Terminating the Current Iteration

The break statement can be used to terminate either a for or a while loop. There is another statement you can use to terminate only the current iteration of a loop, moving on to the next iteration immediately.

In the final example for this lesson, we'll process lines of input from the user. The user will indicate the end of their input by entering a blank line (simply pressing the Enter key), but we want them to be able to add comments to their input by entering lines beginning with the # character. These lines shouldn't be processed; they are just there to inform the reader. (Python also accepts comments—the # character tells the interpreter to ignore everything else up to the end of the line.) We aren't especially concerned with the processing done on each line, so in this example we'll just use the len() function to print the length.

A comment should be indicated by the first printable character. Put this in a file called length_counter.py:

Code
"""Demonstrating the continue statement."""

while True:
    s = input("Enter a line (or Enter to quit): ")
    if not s:
        break
    if s.startswith("#"):
        continue
    print("Length", len(s))

Run it. Enter several lines, including at least one comment line that begins with "#". Comment lines are processed differently from regular lines because of the continue statement, which immediately causes the program to loop and ask for another input. There are other ways you could have achieved the same result.

Feel the Power

Once you understand how looping logic works, you're well on the way to comprehending the power of computers. Looping allows you to tell the computer to repeat the same set of instructions again and again and again...

Python does have easier ways to perform the tasks you programmed in this lesson, but we wanted you to understand what's going on behind the scenes first. Start an interactive session and enter the following expressions:

Code and output
>>> "spaces are our friends".find(" ")
6
>>> "What\tis a   word?".split()
['What', 'is', 'a', 'word?']
>>>

The find() string method locates a given character inside the string (it finds the first occurrence of the string passed as its argument). The split() string method, when called without arguments, splits the string up into its constituent words, which are assumed to be separated by one or more whitespace characters. The strings inside the square brackets constitute a list. We'll be looking at those (and their cousins, the tuples) in the next lesson.

Well done for sticking with it! Now you have a grasp of a lot of the basics, you'll be able to take on more complex programming challenges. See you at the next lesson!