05. While 循环
While 循环
For 循环是 "定迭代" 的一种,它表示循环主体将执行指定次数。列表的 for 循环针对列表中的每个元素执行一次主体。使用
range
函数的 for 循环,其执行次数将由 range 函数调用指定。
这种迭代与 "不定迭代" 不同,后者指循环重复未知次数,直到满足某些条件时循环才会结束。下面这个示例将模拟二十一点发牌,使用 while 循环将卡片牌堆拖到手牌中,在手牌的值大于或等于 17 时停止。
card_deck = [4, 11, 8, 5, 13, 2, 8, 10]
hand = []
while sum(hand) <= 17:
hand.append(card_deck.pop())
print(hand)
这个示例中有一个新的函数
sum
和一个新的列表方法
pop
。
sum
非常直观,它用于计算列表中元素的总和。
pop
方法与
append
方法相反,
pop
从列表中移除一个元素并返回它。大家可以在
官方文档
中阅读更多关于 pop 方法的内容。
下面我们来看一下 while 循环的语法:

-
关键字
While
表示这是一个 while 循环 -
接下来是一个测试表达式,在该示例中表达式为
sum(hand) <= 21
。如果表达式为真,将执行循环主体,之后将再次判断该表达式是否为真。这一过程重复判断测试表达式的真假,并运行循环主体,直到表达式变为 false。 -
循环主体前需要缩进四个空格。循环主体应该以某种方式修改测试表达式中的变量。如果测试表达式的值没有改变,这将导致一个无限循环!在上面的示例中,循环主体将数字追加到了
hand
列表中,因此增加了sum(hand)
的值。
练习:最大平方数
请在下面的练习中完成 nearest_square 函数。该函数取一个整数参数
limit
,并返回一个小于
limit
的最大平方数。平方数是整数乘以自身的乘积,例如 6*6 等于 36,所以 36 是一个平方数。
这个代码有多种编写方法,但是我建议大家使用一个 while 循环!
下面是一个测试用例,在函数编写完成后,你可以使用它来测试自己的代码。当然你也可以随意使用其他数据进行测试。
test1 = nearest_square(40)
print("expected result: 36, actual result: {}".format(test1))
Start Quiz:
#TODO: Implement the nearest_square function
break
停止
For 循环迭代序列中的每个元素,而 while 循环在满足条件时停止迭代。在大多数情况下,这两种用法就已经足够了,但我们有时候需要更精确地控制循环何时结束。这时我们就需要使用关键字
break
了。
循环在遇到 break 时便会立即停止。如果检测到已经满足某些条件,那么我们可以使用这些条件来结束循环。在
for
循环和
while
循环中,我们都可以使用
break
。
我们将通过下面的示例学习如何使用
break
。
假设你想按照一个货物列表来装载货船。每个货物都具有一定的重量,但货船有最大载重限制。在理想情况下,我们希望能够装载所有货物,同时避免货船超载。因此,当货物达到货船的额定载重时,应停止装载。所以在这里我们将使用一个
for
循环,来记录装载的货物以及总重量。一旦所装载的货物达到了货船的最大载重,应使用
break
语句停止装载。
注意:
下方示例中的
manifest
是一个由列表组成的列表。我们以前接触过列表,也知道有些列表元素本身就是列表,而
manifest
变量就是这种情况。
manifest
列表中的每个元素本身就是一个列表,它包含两个元素:货物名称和货物重量。
# each item in the manifest is an item and its weight
manifest = [["bananas", 15], ["mattresses", 34], ["dog kennels",42], ["machine that goes ping!", 120], ["tea chests", 10], ["cheeses", 0]]
cargo_weight = 0
cargo_hold = []
for cargo in manifest:
if cargo_weight >= 100:
break
else:
cargo_hold.append(cargo[0])
cargo_weight += cargo[1]
上方这段代码旨在避免船上货物的重量超过规定的限值 100。现在我们来检查一下装载在船上的货物重量。
>>> print(cargo_weight)
211
>>> print(cargo_hold)
['bananas', 'mattresses', 'dog kennels', 'machine that goes ping!']
上方的结果好像不太对劲,货船装载的货物严重超过了重量限制。尽管 break 语句阻止了我们将每一件货物都放在船上,但最后仍然超过了限制。
单看上方的代码我们很难判断哪里出了问题。在这里我们可以在代码中使用
print
函数来查看问题出在哪里。这是一个非常方便的方法,因为随着代码的逐步运行,它可以让我们深入了解数据状态。如果打印的提示正确(并给出上下文),这可能有助于我们找到错误。
我们在下方的代码中添加了调试语句:
cargo_weight = 0
cargo_hold = []
for cargo in manifest:
print("debug: the weight is currently: {}".format(cargo_weight))
if cargo_weight >= 100:
print("debug: breaking loop now!")
break
else:
print("debug: adding item: {}".format(cargo[0]))
print("debug: with weight: {}".format(cargo[1]))
cargo_hold.append(cargo[0])
cargo_weight += cargo[1]
以下是带标注循环的输出:
debug: the weight is currently: 0
debug: adding item: bananas
debug: with weight: 15
debug: the weight is currently: 15
debug: adding item: mattresses
debug: with weight: 34
debug: the weight is currently: 49
debug: adding item: dog kennels
debug: with weight: 42
debug: the weight is currently: 91
debug: adding item: machine that goes ping!
debug: with weight: 120
debug: the weight is currently: 211
debug: breaking loop now!
通过这些调试日志,我们可以看到循环正确地将货物添加到货船中,但是在满足重量限制之后,还增加了一个额外货物。
思考
QUESTION:
大家知道为什么列表中添加了一个额外的货物吗?请告诉我们你的想法,并查看我们的想法。
ANSWER:
感谢大家思考!问题是导致循环
break
的
if
条件只有在
当前
重量超过限制时才会触发。相反,应该检查添加下一个货物后的
新
重量是否超过限制。
这段新代码将解决问题:
for cargo in manifest:
if cargo_weight + cargo[1] >= 100:
break
else:
cargo_hold.append(cargo[0])
cargo_weight += cargo[1]
可以再次添加
print
语句,并看看其如何运行。
练习:断开字符串
请在下方的练习中使用 break 语句来编写自己的循环。你的任务是创建一个长度为 140 个字符的字符串
news_ticker
。你可以从
headlines
列表添加标题,并在每个标题之间插入一个空格。当
news_ticker
的长度超过 140 个字符时,你可以从中间截断最后一个标题,使字符长度保持在 140。
请记住,在 for 循环和 while 循环中均可使用
break
。请在下方练习中使用你心目中最合适的循环,你也可以考虑在代码中添加
print
语句来帮助你解决错误。
Start Quiz:
headlines = ["Local Bear Eaten by Man",
"Legislature Announces New Laws",
"Peasant Discovers Violence Inherent in System",
"Cat Rescues Fireman Stuck in Tree",
"Brave Knight Runs Away",
"Papperbok Review: Totally Triffic"]
news_ticker = ""
# TODO: set news_ticker to a string that contains no more than 140 characters long.
# HINT: modify the headlines list to verify your loop works with different inputs