返回介绍

第 5 章 迭代

发布于 2025-02-19 23:42:46 字数 7644 浏览 0 评论 0 收藏 0

5.1 更新变量

赋值语句的常见模式是对变量进行更新,变量的新值依赖于旧值。

x = x+1

这条语句的作用是:得到 x 的当前值,加一,然后将相加结果作为新值赋予 x。

如果更新一个不存在的变量,那么会出错。这是因为 Python 在给 x 赋值之前,首先计算等号右边:

>>> x = x+1
NameError: name 'x' is not defined

在更新变量之前,必须初始化,通常使用简单的赋值语句:

>>> x = 0
>>> x = x+1

通过加一操作更新变量称为增量更新,减一操作称为减量更新。

5.2 while 语句

计算机经常用于执行一些重复性的任务。对计算机来说,执行相同或相似的任务而不出错,这很简单,但人就做不好。迭代很常见,Python 提供了一些功能语句,使这类任务变得更加简单。

Python 的一种迭代形式是 while 语句。下面是一个简单的例子,从 5 开始倒数,然后打印出“Blastoff!”。

n = 5
while n > 0:
  print n
  n = n-1
print 'Blastoff!'

几乎可以像读英文一样,读懂这条 while 语句。它的作用是:当 n 大于 0 时,显示 n 的值,然后对 n 减 1。当 n 等于 0 时,结束 while 语句,显示“blastoff!”。

严格说, while 语句的执行流程如下:

  1. 计算条件表达式的值,判断是 True 或 False。
  2. 如果为 False,结束 while 语句并执行下一条语句。
  3. 如果为 True,执行 while 中的语句体,然后返回步骤 1。

此类执行流程称为循环。执行到第三步又返回到顶部。每执行一次循环体,称为一次迭代。上面的循环,我们可以说“它进行了五次迭代”,表示循环体被执行了五次。

循环体会改变一个或多个变量的值。因此当条件不满足时,循环结束。有一种变量在每次循环执行时其值都会变化,并控制循环什么时候结束,这种变量称为迭代变量。如果没有迭代变量,循环就会永远执行下去,导致无限循环。

5.3 无限循环

对于程序员来说,无限循环的有趣实例就是洗发水的说明书,“泡沫,冲洗,重复”。这就是一个无限循环,没有迭代变量来表明什么时候结束这个循环。

上面的倒数例子中,循环的确是结束了。因为 n 值的个数是有限的,我们可以看到 n 值随着循环的执行不断减小,最终变为 0。有些情况的循环明显是无限的,这是因为它根本就没有迭代变量。

5.4 “无限循环”与 break 语句

有时候循环运行到一半时,你还没意识到这时候该结束循环了。在这种情况下,你可以写一个无限的循环,然后使用 break 语句跳出循环。

下面的代码明显是一个无限循环,while 语句的逻辑表达式是常量 True:

n = 10
while True:
  print n,
  n = n - 1
print 'Done!'

如果犯了这个错误并且运行这个代码,你会很快学会如何停止一个正在运行的 Python 进程,或者找到计算机的关机按钮。由于循环顶部的逻辑表达式是常量 True,所以循环条件一直都满足,这个程序会一直运行下去,直到计算机没电。

虽然这是一个不正常的无限循环,我们还是可以使用这种模式来建立有用的循环。只要将 break 语句放进循环体,明确退出条件及行为。当达到结束条件时,就可以结束循环。

举例来说,如果想要用户直到输入 done 时结束的话,代码可以这样写:

while True:
  line = raw_input('> ')
  if line == 'done':
    break
  print line
print 'Done!'

这个循环的条件是 True 且不会变,因此循环会一直执行下去,直到触发 break 语句。

每次执行这个循环,它都会提示用户一个尖括号。如果用户输入 done,那么 break 语句就会结束这个循环。否则,这个程序会一直提示用户进行输入,回到顶部继续执行。下面是一个程序运行的结果演示:

> hello there
hello there
> finished
finished
> done
Done!

while 语句的这种写法很常见。你可以在循环中的任何位置检查条件(不仅局限于顶部),并且可以主动定义停止条件(当发生什么就停止),而不是被动等待判断(一直运行直到发生什么)。

5.5 使用 continue 语句结束迭代

有时在循环的迭代中,你想要结束当前迭代,立刻进行下一轮迭代。在这种情况下,使用 continue 语句跳入下一轮迭代,无需完成当前迭代的循环体。

下面的循环例子不断打印输入值,直到用户输入“done”才会结束。但是,#号开头的输入不会被打印出来(这有点像 Python 的注释)。

运行一下这个加入了 continue 语句的新程序。

while True:
  line = raw_input('> ')
  if line[0] == '#' :
    continue
  if line == 'done':
    break
  print line
print 'Done!'

除了#号开头的行,其他所有的行都被打印出来。当 continue 语句被执行,当前迭代会结束,跳到 while 语句的开头执行下一轮循环,这样也就跳过了 print 语句。

5.6 使用 for 语句定义循环

有时候我们需要要遍历一组东西,例如,单词列表,文件的每一行或是一组数字。遍历一组东西,可以用 for 语句来构造循环。因为 wile 语句是简单地进行循环,直到条件变为 False,我们称其为无限循环。与之不同的是,for 语句是对已知的数据项集合进行循环,因此它的迭代次数取决于数据项的个数。

for 循环和 while 循环的语法相似,下面是一个 for 语句和循环体代码示例:

friends = ['Joseph', 'Glenn', 'Sally']
for friend in friends:
  print 'Happy New Year:', friend
print 'Done!'

在 Python 语法中,friends 变量是包含三个字符串的列表1 。for 循环遍历整个列表,依次打印每个字符串这三个字符,输出结果如下所示:

Happy New Year: Joseph
Happy New Year: Glenn
Happy New Year: Sally
Done!

如果用英语来解释这个 for 循环,就不如 while 循环的解释那么直接。你可以把它当做一个朋友名单,那么这段代码的作用是:对 friends 集合中的每个朋友执行 for 循环体。

观察这个 for 循环,for 和 in 是 Python 的保留关键字,friend 和 friends 是变量。

for friend in friends:

print ’Happy New Year’, friend

具体来说,friend 是 for 循环的迭代变量。变量 friend 的值在每次迭代时都会改变,并控制 for 循环什么时候结束。这个迭代变量取得 friends 中存储的三个字符串。

5.7 循环模式

我们经常使用 for 循环或 while 循环来遍历列表或文件的内容,还会通过浏览来寻找一组数值中的最大值或最小值。

此类循环的构造方法如下:

  • 循环开始之前初始化一个或多个变量。
  • 在循环体中对每个数据项进行计算,这样可能会改变循环体中变量的值。
  • 循环结束时查看最终变量。

我们会用一组数字来展示这些循环模式的理念和构造方法。

5.7.1 统计与求和循环

举例来说,为了统计一个列表的数据项个数, for 循环编写如下:

count = 0
for itervar in [3, 41, 12, 9, 74, 15]:
  count = count + 1
print 'Count: ', count

循环开始之前将变量 count 的值设为 0,然后用一个 for 循环来遍历数值列表。迭代变量命名为 itervar。虽然我们并不在循环体中使用它,但它控制着循环,让循环体为每一个列表值执行一次。

在循环体中,列表的每个值都会导致 count 值加一。随着循环的执行,count 值就是“当前”所看到的。

循环一旦结束,count 值就等于列表中数值的个数。在循环最后,总数“落入我们手中”。通过构造这个循环,在循环结束时我们得到了想要的。

另一个相似的循环求出一组数值的总和:

total = 0
for itervar in [3, 41, 12, 9, 74, 15]:
  total = total + itervar
print 'Total: ', total

在这个循环中,我们用到了迭代变量。不是之前循环中为 count 变量简单加一,而是在每次循环中加上实际的数字(如 3、41、12 等)。total 变量的作用是求出目前的累计值。在循环开始之前,由于还没有遇到任何值,所以 total 值是 0。循环中会累加,total 最终值是所有数字的总和。

随着循环的进行,total 累积了列表各项的和。这样的变量有时候被称为累加器(accumulator)。

不管统计循环还是求和循环,在实际使用中都不是很有用。这是因为 Python 提供了内置函数 len() 和 sum(),分别计算列表元素的个数和列表各项的总和。

5.7.2 最大值与最小值循环

找出列表或者序列中的最大值,构造如下循环:

largest = None
print 'Before:', largest
for itervar in [3, 41, 12, 9, 74, 15]:
  if largest is None or itervar > largest :
    largest = itervar
  print 'Loop:', itervar, largest
print 'Largest:', largest

程序执行结果如下:

Before: None
Loop: 3 3
Loop: 41 41
Loop: 12 41
Loop: 9 41
Loop: 74 74
Loop: 15 74
Largest: 74

largest 变量是“目前我们看到的最大值”。在循环开始之前,将 largest 设为常量 None。None 是一个特殊的常量,表示变量为“空”。

在循环开始之前,我们没有遇到任何值,所以 largest 值为 None。当循环开始执行,如果 largest 为 None,则将第一个值作为目前看到的最大值。可以看到,第一轮迭代中 itervar 的值是 3,largest 的值是 None,所以立即将 largest 的值变为 3。

第一次迭代之后,最大值就不是 None 了。复合逻辑表达式的第二部分设置了触发器,检查 itervar 值是否大于 largest 值。如果当前值大于 largest 值,就会将更大的新值赋予 largest。从程序输出可以看出,largest 值从 3 变为 41,然后变为 74。

循环结束后遍历了所有的值,largest 值已经是整个列表中的最大值了。

计算最小值的代码仅需要做很小改动:

smallest = None
print 'Before:', smallest
for itervar in [3, 41, 12, 9, 74, 15]:
  if smallest is None or itervar < smallest:
    smallest = itervar
  print 'Loop:', itervar, smallest
print 'Smallest:', smallest

同样的,smallest 值在循环前、循环中与循环后都是“目前看到的最小值”。循环结束后,smallest 值就是整个列表的最小值。

统计和求和同样有 Python 内置函数支持,比如,使用 max() 函数和 min() 函数可以不用到循环代码。

下面是 Python 内置函数 min() 的简化版代码:

def min(values):
  smallest = None
  for value in values:
    if smallest is None or value < smallest:
      smallest = value
  return smallest

在这段代码中,我们移除了所有的 print 语句,与 Python 内置函数 min() 基本等价。

5.8 调试

当程序越写越长,你就会发现需要花费更多的时间来调试。代码越多意味着犯错的机会越大,隐藏的错误也就越多。

相反,试着将问题分为两部分。在程序的中间位置,寻找一处可验证的代码,插入一个 print 语句(或者其它可验证效果的语句),然后运行程序。

如果中间点检查出错,那么问题肯定出在程序的前半部分。如果中间点检查没错,问题就出在程序的后半部分。

每执行一次这样的检查,你就会把代码范围缩减一半。如果代码少于 100 行,进行 6 次之后,就只剩下一两行,理论上至少是这样。

实际上,“程序的中间位置”并不是很明显,也可能没法进行检查。统计行数然后除以 2,找到精确的中间位置代码行,这种做法没有意义。一般做法是,考虑程序中容易出现错误的地方,进行检查。选择你认为极有可能会出错的位置前后,设置检查点。

5.9 术语

累加器: 循环语句中用来累积结果的变量。

计数器: 循环语句中用来计算发生次数的变量。计数器初始化为 0,每次需要计数时,增加它的值。

减量: 减少变量值的更新。

初始化: 为随后会更新的变量赋予初始值的语句。

增量: 增加变量值的更新(通常是加一)。

无限循环: 终止条件无法达到或者没有终止条件的循环。

迭代: 通过递归函数调用或者循环来重复执行一组语句。

5.10 练习

习题 5.1 编写一个程序,重复读取数据,直到用户输入“done”。一旦输入“done”,打印总和、个数与平均值。如果用户输入的不是数字,使用 try 和 except 捕获异常,打印错误信息,然后跳过继续执行循环。

习题 5.2 编写一个程序,提示用户输入一组数字,输出最大值和最小值,不要求平均值。

1. 第 8 章会详细介绍列表。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文