3.12. for loops

Like most other languages, Python has for loops. The only reason you haven't seen them until now is that Python is good at so many other things that you don't need them as often.

Most other languages don't have a powerful list datatype like Python, so you end up doing a lot of manual work, specifying a start, end, and step to define a range of integers or characters or other iteratable entities. But in Python, a for loop simply iterates over a list, the same way list comprehensions work.

Пример 3.27. Introducing the for loop

>>> li = ['a', 'b', 'e'] >>> for s in li: 1 ... print s 2 a b e >>> print "\n".join(li) 3 a b e
1 The syntax for a for loop is similar to list comprehensions. li is a list, and s will take the value of each element in turn, starting from the first element.
2 Like an if statement or any other indented block, a for loop can have any number of lines of code in it.
3 This is the reason you haven't seen the for loop yet: we haven't needed it yet. It's amazing how often you use for loops in other languages when all you really want is a join or a list comprehension.

Пример 3.28. Simple counters

>>> for i in range(5): 1 ... print i 0 1 2 3 4 >>> li = ['a', 'b', 'c', 'd', 'e'] >>> for i in range(len(li)): 2 ... print li[i] a b c d e
1 Doing a “normal” (by Visual Basic standards) counter for loop is also simple. As we saw in Пример 1.27. Присваивание идущих подряд значений, range produces a list of integers, which we then loop through. I know it looks a bit odd, but it is occasionally (and I stress occasionally) useful to have a counter loop.
2 Don't ever do this. This is Visual Basic-style thinking. Break out of it. Just iterate through the list, as shown in the previous example.

Пример 3.29. Iterating through a dictionary

>>> for k, v in os.environ.items(): 1 2 ... print "%s=%s" % (k, v) USERPROFILE=C:\Documents and Settings\mpilgrim OS=Windows_NT COMPUTERNAME=MPILGRIM USERNAME=mpilgrim [...snip...] >>> print "\n".join(["%s=%s" % (k, v) for k, v in os.environ.items()]) 3 USERPROFILE=C:\Documents and Settings\mpilgrim OS=Windows_NT COMPUTERNAME=MPILGRIM USERNAME=mpilgrim [...snip...]
1 os.environ is a dictionary of the environment variables defined on your system. In Windows, these are your user and system variables accessible from MS-DOS. In UNIX, they are the variables exported in your shell's startup scripts. In Mac OS, there is no concept of environment variables, so this dictionary is empty.
2 os.environ.items() returns a list of tuples: [(key1, value1), (key2, value2), ...]. The for loop iterates through this list. The first round, it assigns key1 to k and value1 to v, so k = USERPROFILE and v = C:\Documents and Settings\mpilgrim. The second round, k gets the second key, OS, and v gets the corresponding value, Windows_NT.
3 With multi-variable assignment and list comprehensions, you can replace the entire for loop with a single statement. Whether you actually do this in real code is a matter of personal coding style; I like it because it makes it clear that what we're doing is mapping a dictionary into a list, then joining the list into a single string. Other programmers prefer to write this out as a for loop. Note that the output is the same in either case, although this version is slightly faster, because there is only one print statement instead of many.

Пример 3.30. for loop in MP3FileInfo

tagDataMap = {"title" : ( 3, 33, stripnulls), "artist" : ( 33, 63, stripnulls), "album" : ( 63, 93, stripnulls), "year" : ( 93, 97, stripnulls), "comment" : ( 97, 126, stripnulls), "genre" : (127, 128, ord)} 1 . . . if tagdata[:3] == "TAG": for tag, (start, end, parseFunc) in self.tagDataMap.items(): 2 self[tag] = parseFunc(tagdata[start:end]) 3
1 tagDataMap is a class attribute that defines the tags we're looking for in an MP3 file. Tags are stored in fixed-length fields; once we read the last 128 bytes of the file, bytes 3 through 32 of those are always the song title, 33-62 are always the artist name, 63-92 the album name, and so forth. Note that tagDataMap is a dictionary of tuples, and each tuple contains two integers and a function reference.
2 This looks complicated, but it's not. The structure of the for variables matches the structure of the elements of the list returned by items. Remember, items returns a list of tuples of the form (key, value). The first element of that list is ("title", (3, 33, <function stripnulls>)), so the first time around the loop, tag gets "title", start gets 3, end gets 33, and parseFunc gets the function stripnulls.
3 Now that we've extracted all the parameters for a single MP3 tag, saving the tag data is easy. We slice tagdata from start to end to get the actual data for this tag, call parseFunc to post-process the data, and assign this as the value for the key tag in the pseudo-dictionary self. After iterating through all the elements in tagDataMap, self has the values for all the tags, and you know what that looks like.