Go to: Na-Rae Han's home page  

Python 3 Notes

        [ HOME | LING 1330/2330 ]

More on for Loops

<< Previous Note           Next Note >>
On this page: for ... in over list, string, dictionary. dict.items(), range(), enumerate(), break, nested for loops.

for Loops Over a List

As mentioned briefly in Tutorial 14, the for ... in loop is adaptive: you can use it with any sequence type (list, string, tuple) plus dictionaries. The most prototypical use of for ... in loop is over a list. Below, it is used to add up the numbers in a list:
>>> total = 0
>>> for n in [5.99, 12.99, 20.99, 129.99]: 
        total += n
        print('Total is now', total)

Total is now 5.99
Total is now 18.98
Total is now 39.97
Total is now 169.96		
>>> total  

for Loops Over a String

When used on a string, the looping has to go through every something. Well, a string is a sequence of characters, so the iteration is done on every character:
>>> for x in 'school': 

for Loops Over a Dictionary

Naturally, we'd also want to be able to loop over a dictionary. When for ... in is used on a dictionary, looping is done over its keys, and not over the values or the key:value pairs:
>>> simpsons = {'Homer':36, 'Marge':35, 'Bart':10, 'Lisa':8}
>>> for s in simpsons:              # s iterates over keys in simpsons
Of course, the values are retrievable via the keys. Hence, printing both the key and the value looks like:
>>> for s in simpsons:              # s iterates over keys in simpsons
        print(s, simpsons[s])       # key, value  
Homer 36
Lisa 8
Marge 35
Bart 10 
An alternative is to explicitly instruct the for loop to iterate over the key:value pairs. The .items() method on a dictionary induces a pseudo-list of (key, value) tuples. The for loop then can iterate over this list, and the bound variable should also be the tuple type:
>>> simpsons.items()             # returns a quasi-list of (key, value) pairs
dict_items([('Homer', 36), ('Lisa', 8), ('Marge', 35), ('Bart', 10)]) 
>>> for (k,v) in simpsons.items():    # iterate over (key, value) list
        print(k, v)                   # key, value  
Homer 36
Lisa 8
Marge 35
Bart 10 
Note that the iteration is in no particular order, although it stays consistent. That's because dictionaries are inherently orderless. If you want to go through the dictionary in a particular order (say, alphabetical or numerical), you will have to sort. See Sorting for details.

Indexing With range() Function

range() is a function that's often used with a for loop. range(x,y) creates a list-like object starting with integer x and ending BEFORE y. The starting point x can be omitted, in which case the list starts with 0. In a looping environment range() works as expected. In a non-iterative environment, however, you will need to plug in the range() function's return value into list() to view it as a list:
>>> for i in range(4):    # range() in iterative environment
>>> range(4)              # non-iterative context: content not visible
>>> list(range(4))        # force into list type to see what's inside
[0, 1, 2, 3] 
>>> list(range(2,8))
[2, 3, 4, 5, 6, 7] 
The reason why range() is used often with a for loop is the following. In the 'penguin' example above, what if you want to also print out the index of each character? The way the loop is written, i is bound to the character itself, and there's nothing that references the location of an individual character. range() solves this. First, range() together with len('penguin') produces a list of indexes for the word:
>>> len('penguin')
>>> list(range(len('penguin')))
[0, 1, 2, 3, 4, 5, 6] 
Now, you can iterate through this list of indexes, and it is easy enough to get to the character once you have its index:
>>> for i in range(len('penguin')): 
        print(i, 'penguin'[i]) 
0 p
1 e
2 n
3 g
4 u
5 i
6 n 

Referencing Index with enumerate() Function

enumerate() is another handy function that is often used in conjunction with a for loop. It takes a sequence-type argument, meaning both strings and lists, and returns a pseudo-list of (index, element) pairs. In a looping environment, enumerate() works transparently. In a non-iterative environment, however, you will need to plug in the function's return value into list() to view it as a list:
>>> enumerate('tiger')              # non-iterative context: content not visible
<enumerate object at 0x0304BDA0> 
>>> list(enumerate('tiger'))        # force into list type to see what's inside
[(0, 't'), (1, 'i'), (2, 'g'), (3, 'e'), (4, 'r')] 
Just like the .items() dictionary method lets us access a key and its value together, this gives us a handy way to access a sequence element and its index side-by-side. You achieve this by having the for loop directly reference the (index, element) pair, as (i, e) in the example below:
>>> for (i, e) in enumerate('tiger'):    # i is bound to index, e bound to each letter
        print(i, 'is the index for', e)	  

0 is the index for t
1 is the index for i
2 is the index for g
3 is the index for e
4 is the index for r 
>>> for (i, e) in enumerate([80, 95, 72, 88]):    # i is index, e is list element
        print(e, 'is at', i)	  

80 is at 0
95 is at 1
72 is at 2
88 is at 3 

Exiting Loop Early with break

Sometimes, you want to continue looping only until a certain condition is met. Python's break keyword lets you do that. Suppose, for a given word, you only want to print out the word-initial "consonant" characters. You achieve it by breaking out of the loop upon encountering the first "vowel" character:
>>> for x in 'school': 
        if x in 'aeiou': break      # x is a vowel! breaking out.
Here, when x gets bound to 'o', the break statement executes and you exit the loop before the print() function runs. If the break condition was placed at the bottom, however, 'o' would still print before the loop terminates:
>>> for x in 'school': 
        if x in 'aeiou': break  


Nested for Loops

If you think a simple for loop is easy, nested for loops can be a bit difficult to wrap your head around. Below, the inner loop repeats 4 times inside another loop, which itself repeats 4 times:
>>> for x in 'abcd': 
        for y in 'abcd': 
            print(x, y) 
a a
a b
a c
a d
b a
b b
b c
b d
c a
c b
c c
c d
d a
d b
d c
d d
Why stop at two? Try a 3-level for loop from Anne Dawson's page. Search for "nested for loop".