Section 8.6. for Statement


8.6. for Statement

The other looping mechanism in Python comes to us in the form of the for statement. It represents the single most powerful looping construct in Python. It can loop over sequence members, it is used in list comprehensions and generator expressions, and it knows how to call an iterator's next() method and gracefully ends by catching StopIteration exceptions (all under the covers). If you are new to Python, we will tell you now that you will be using for statements a lot.

Unlike the traditional conditional looping for statement found in mainstream languages like C/C++, Fortran, or Java, Python's for is more akin to a shell or scripting language's iterative foreach loop.

8.6.1. General Syntax

The for loop traverses through individual elements of an iterable (like a sequence or iterator) and terminates when all the items are exhausted. Here is its syntax:

for iter_var in iterable:     suite_to_repeat


With each loop, the iter_var iteration variable is set to the current element of the iterable (sequence, iterator, or object that supports iteration), presumably for use in suite_to_repeat.

8.6.2. Used with Sequence Types

In this section, we will see how the for loop works with the different sequence types. The examples will include string, list, and tuple types.

>>> for each Letter in 'Names': ...     print 'current letter:', each Letter ... current letter: N current letter: a current letter: m current letter: e current letter: s


When iterating over a string, the iteration variable will always consist of only single characters (strings of length 1). Such constructs may not necessarily be useful. When seeking characters in a string, more often than not, the programmer will either use in to test for membership, or one of the string module functions or string methods to check for sub strings.

One place where seeing individual characters does come in handy is during the debugging of sequences in a for loop in an application where you are expecting strings or entire objects to show up in your print statements. If you see individual characters, this is usually a sign that you received a single string rather than a sequence of objects.

There are three basic ways of iterating over a sequence:

Iterating by Sequence Item

>>> nameList = ['Walter', "Nicole", 'Steven', 'Henry'] >>> for eachName in nameList: ...     print eachName, "Lim" ... Walter Lim Nicole Lim Steven Lim Henry Lim


In the above example, a list is iterated over, and for each iteration, the eachName variable contains the list element that we are on for that particular iteration of the loop.

Iterating by Sequence Index

An alternative way of iterating through each item is by index offset into the sequence itself:

>>> nameList = ['Cathy', "Terry", 'Joe', 'Heather', 'Lucy'] >>> for nameIndex in range(len(nameList)): ...     print "Liu,", nameList[nameIndex] ... Liu, Cathy Liu, Terry Liu, Joe Liu, Heather Liu, Lucy


Rather than iterating through the elements themselves, we are iterating through the indices of the list.

We employ the assistance of the len() built-in function, which provides the total number of elements in the tuple as well as the range() built-in function (which we will discuss in more detail below) to give us the actual sequence to iterate over.

>>> len(nameList) 5 >>> range(len(nameList)) [0, 1, 2, 3, 4]


Using range(), we obtain a list of the indexes that nameIndex iterates over; and using the slice/subscript operator ( [ ] ), we can obtain the corresponding sequence element.

Those of you who are performance pundits will no doubt recognize that iteration by sequence item wins over iterating via index. If not, this is something to think about. (See Exercise 8-13.)

Iterating with Item and Index

The best of both worlds comes from using the enumerate() built-in function, which was added to Python in version 2.3. Enough said ... here is some code:

>>> nameList = ['Donn', 'Shirley', 'Ben', 'Janice', ...     'David', 'Yen', 'Wendy'] >>> for i, eachLee in enumerate(nameList): ...     print "%d %s Lee" % (i+1, eachLee) ... 1 Donn Lee 2 Shirley Lee 3 Ben Lee 4 Janice Lee 5 David Lee 6 Yen Lee 7 Wendy Lee


8.6.3. Used with Iterator Types

Using for loops with iterators is identical to using them with sequences. The only difference is that the for statement must do a little bit of extra work on your behalf. An iterator does not represent a set of items to loop over.

Instead, iterator objects have a next() method, which is called to get subsequent items. When the set of items has been exhausted, the iterator raises the StopIteration exception to signal that it has finished. Calling next() and catching StopIteration is built-in to the for statement.

When you are using a for loop with an iterator, the code is nearly identical to that of looping over sequence items. In fact, for most cases, you cannot tell that you are iterating over a sequence or an iterator, hence the reason why you will see us refer to iterating over an iterable, which could mean a sequence, an iterator, or any object that supports iteration, e.g., has a next() method.

8.6.4. range() Built-in Function

We mentioned above during our introduction to Python's for loop that it is an iterative looping mechanism. Python also provides a tool that will let us use the for statement in a traditional pseudo-conditional setting, i.e., when counting from one number to another and quitting once the final number has been reached or some condition is no longer satisfied.

The built-in function range() can turn your foreach-like for loop back into one that you are more familiar with, i.e., counting from 0 to 10, or counting from 10 to 100 in increments of 5.

range() Full Syntax

Python presents two different ways to use range(). The full syntax requires that two or all three integer arguments are present:

range(start, end, step=1)


range() will then return a list where for any k, start <= k < end and k iterates from start to end in increments of step. step cannot be 0, or an error condition will occur.

>>> range(2, 19, 3) [2, 5, 8, 11, 14, 17]


If step is omitted and only two arguments given, step takes a default value of 1.

>>> range(3, 7) [3, 4, 5, 6]


Let's take a look at an example used in the interpreter environment:

>>> for eachVal in range(2, 19, 3): ...      print "value is:", eachVal ... value is: 2 value is: 5 value is: 8 value is: 11 value is: 14 value is: 17


Our for loop now "counts" from 2 to 19, incrementing by steps of 3. If you are familiar with C, then you will notice the direct correlation between the arguments of range() and those of the variables in the C for loop:

/* equivalent loop in C */ for (eachVal = 2; eachVal < 19; eachVal += 3) {    printf("value is: %d\n", eachVal); }


Although it seems like a conditional loop now (checking if eachVal < 19), reality tells us that range() takes our conditions and generates a list that meets our criteria, which in turn is used by the same Python for statement.

range() Abbreviated Syntax

range() also has two abbreviated syntax formats:

range(end) range(start, end)


We saw the shortest syntax earlier in Chapter 2. Given only a single value, start defaults to 0, step defaults to 1, and range() returns a list of numbers from zero up to the argument end:

>>> range(5) [0, 1, 2, 3, 4]


Given two values, this midsized version of range() is exactly the same as the long version of range() taking two parameters with step defaulting to 1. We will now take this to the Python interpreter and plug in for and print statements to arrive at:

>>> for count in range(2, 5): ...     print count ... 2 3 4


Core Note: Why not just one syntax for range()?

Now that you know both syntaxes for range(), one nagging question you may have is, why not just combine the two into a single one that looks like this?

range(start=0, end, step=1) # invalid


This syntax will work for a single argument or all three, but not two. It is illegal because the presence of step requires start to be given. In other words, you cannot provide end and step in a two-argument version because they will be (mis)interpreted as start and end.


8.6.5. xrange() Built-in Function

xrange() is similar to range() except that if you have a really large range list, xrange() may come in handier because it does not have to make a complete copy of the list in memory. This built-in was made for exclusive use in for loops. It does not make sense outside a for loop. Also, as you can imagine, the performance will not be as good because the entire list is not in memory. In future versions of Python, range() will eventually become like xrange(), returing an iterable object (not a list nor an iterator though)it will be similar to views as discussed in the previous chapter.

8.6.6. Sequence-Related Built-in Functions

sorted(), reversed(), enumerate(), zip()

Below are some examples of using these loop-oriented sequence-related functions. The reason why they are "sequence-related" is that half of them (sorted() and zip()) return a real sequence (list), while the other two (reversed() and enumerate()) return iterators (sequence-like).

>>> albums = ('Poe', 'Gaudi', 'Freud', 'Poe2') >>> years = (1976, 1987, 1990, 2003) >>> for album in sorted(albums): ...     print album, ... Freud Gaudi Poe Poe2 >>> >>> for album in reversed(albums): ...     print album, ... Poe2 Freud Gaudi Poe >>> >>> for i, album in enumerate(albums): ...     print i, album ... 0 Poe 1 Gaudi 2 Freud 3 Poe2 >>> >>> for album, yr in zip(albums, years): ...     print yr, album ... 1976 Poe 1987 Gaudi 1990 Freud 2003 Poe2


Now that we have covered all the loops Python has to offer, let us take a look at the peripheral commands that typically go together with loops. These include statements to abandon the loop (break) and to immediately begin the next iteration (continue).



Core Python Programming
Core Python Programming (2nd Edition)
ISBN: 0132269937
EAN: 2147483647
Year: 2004
Pages: 334
Authors: Wesley J Chun

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net