for 语句
Python 提供给我们除了while循环语句的另一个循环机制就是 for 语句. 它提供了 Python 中最强大的循环结构. 它可以遍历序列成员, 可以用在 列表解析 和 生成器表达式中, 它会自动地调用迭代器的 next() 方法, 捕获 StopIteration 异常并结束循环(所有这一切都是在内部发生的). 如果你刚刚接触Python 那么我们要告诉你, 在以后你会经常用到它的. 和传统语言(例如 C/C++ , Fortran, 或者 Java )中的 for 语句不同, Python 的 for 更像是 shell 或是脚本语言中的 foreach 循环。
一般语法
for 循环会访问一个可迭代对象(例如序列或是迭代器)中的所有元素, 并在所有条目都处理过后结束循环. 它的语法如下:
for iter_var in iterable:
suite_to_repeat
每次循环, iter_var 迭代变量被设置为可迭代对象(序列, 迭代器, 或者是其他支持迭代的对象)的当前元素, 提供给 suite_to_repeat 语句块使用。
用于序列类型
本文章中我将用 for 循环迭代不同的序列对象. 样例将涵盖字符串, 列表, 以及元组。
>>> for eachLetter in 'Names':
... print 'current letter:', eachLetter
...
current letter: N
current letter: a
current letter: m
current letter: e
current letter: s
当迭代字符串时, 迭代变量只会包含一个字符(长度为 1 的字符串). 但这并不常用。在字符串里中查找字符时, 程序员往往使用 in 来测试成员关系, 或者使用 string 模块中的函数以及字符串方法来检查子字符串。
看到单个的字符在一种情况下有用,即在通过 print 语句调试 for 循环中的序列时, 如果你在应该看到字符串的地方发现的却是单个的字符, 那么很有可能你接受到的是一个字符串, 而不是对象的序列.
迭代序列有三种基本方法:
通过序列项迭代
>>> nameList = ['Walter', "Nicole", 'Steven', 'Henry']
>>> for eachName in nameList:
... print eachName, "Lim"
...
Walter Lim
Nicole Lim
Steven Lim
Henry Lim
在上面的例子中, 我们迭代一个列表. 每次迭代, eacgName 变量都被设置为列表中特定某个元素.
然后我们在代码块中打印出这个变量.
通过序列索引迭代
>>> 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
我们没有迭代元素, 而是通过列表的索引迭代.
这里我们使用了内建的 len() 函数获得序列长度, 使用 range() 函数(我们将在下面详细讨论它)创建了要迭代的序列.
使用项和索引迭代
两全其美的办法是使用内建的 enumerate() 函数, 它是 Python 2.3 的新增内容. 代码如下:
>>> 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
用于迭代器类型
用 for 循环访问迭代器和访问序列的方法差不多. 唯一的区别就是 for 语句会为你做一些额外的事情. 迭代器并不代表循环条目的集合.
迭代器对象有一个 next() 方法, 调用后返回下一个条目. 所有条目迭代完后, 迭代器引发一个 StopIteration 异常告诉程序循环结束. for 语句在内部调用 next() 并捕获异常.
使用迭代器做 for 循环的代码与使用序列条目几乎完全相同. 事实上在大多情况下, 你无法分辨出你迭代的是一个序列还是迭代器, 因此,这就是为什么我们在说要遍历一个迭代器时,实际上可能我们指的是要遍历一个序列,迭代器,或是一个支持迭代的对象(它有 next()方法)
range() 内建函数
我们前面介绍 Python 的 for 循环的时候提到过它是一种迭代的循环机制. Python 同样提供一个工具让我们在传统的伪条件设置下使用 for 声明, 例如从一个数字开始计数到另外个数字, 一旦到达最后的数字或者某个条件不再满足就立刻退出循环.
内建函数 range() 可以把类似 foreach 的 for 循环变成你更加熟悉的语句. 例如从 0 到 10 计数, 或者从 10 到 100 一次递增 5 .
range() 的完整语法
Python 提供了两种不同的方法来调用 range() . 完整语法要求提供两个或三个整数参数:
range(start, end, step =1)
range() 会返回一个包含所有 k 的列表, 这里 start <= k < end , 从 start 到 end , k 每次递增 step . step 不可以为零,否则将发生错误.
>>> range(2, 19, 3)
[2, 5, 8, 11, 14, 17]
如果只给定两个参数,而省略 step, step 就使用默认值 1 .
>>> range(3, 7)
[3, 4, 5, 6]
我们来看看解释器环境下的例子
>>> 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
我们的循环从 2 "数" 到 19 , 每次递增 3 . 如果你对 C 熟悉的话, 你会发现,range()的参数与 C 的 for 循环变量有着直接的关系:
/* equivalent loop in C */
for (eachVal = 2; eachVal < 19; eachVal += 3) {
printf("value is: %d\n", eachVal);
}
虽然看起来像是一个条件循环(检查 eachVal< 19 ), 但实际上是 range() 先用我们指定的条件生成一个列表, 然后把列表用于这个 for 语句.
range() 简略语法
range() 还有两种简略的语法格式:
range(end)
range(start, end)
我们看到过最短的语法 接受一个值, start 默认为 0 , step 默认为 1 , 然后 range()返回从 0 到 end 的数列.
>>> range(5)
[0, 1, 2, 3, 4]
range() 的中型版本和完整版本几乎完全一样, 只是 step 使用默认值 1 . 现在我们在 Python 解释器中试下这条语句:
>>> for count in range(2, 5):
... print count
...
2
3
4
** 核心笔记: 为什么 range() 不是只有一种语法?
你已经知道了 range() 的所有语法, 有些人可能会问一个挑剔的问题, 为什么不把这两种语法合并成一个下面这样的语法?
range(start=0, end, step =1) # 错误
这个语法不可以使用两个参数调用. 因为 step 要求给定 start . 换句话说, 你不能只传递 end 和 step 参数. 因为它们会被解释器误认为是 start 和 end .**
xrange() 内建函数
xrange() 类似 range() , 不过当你有一个很大的范围列表时, xrange() 可能更为适合, 因为它不会在内存里创建列表的完整拷贝. 它只被用在 for 循环中, 在 for 循环外使用它没有意义。同样地, 你可以想到, 它的性能远高出 range(), 因为它不生成整个列表。在 Python 的将来版本中, range() 可能会像 xrange() 一样, 返回一个可迭代对象(不是列表也不是一个迭代器) 。
与序列相关的内建函数
sorted(), reversed(), enumerate(), zip()
下边是使用循环相关和序列相关函数的例子. 为什么它们叫"序列相关"呢? 是因为其中两个函数( sorted() 和 zip() )返回一个序列(列表), 而另外两个函数( reversed() 和 enumerate() ) 返回迭代器(类似序列)
>>> 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
我们已经涵盖了 Python 中的所有循环语句, 下面我们看看循环相关的语句, 包括用于放弃循环的 break 语句, 和立即开始下一次迭代的 continue 语句.