控制流
到目前为止,你写的每个程序都以相同的方式运行:自上而下,一次一行。这对简单的脚本来说是可行的,但真正的程序需要做出决策并重复工作。一个测验需要检查答案是否正确。一个游戏需要持续运行,直到玩家赢或输。本章介绍如何让你的程序进行分支和重复。
比较
在做出决定之前,你需要比较事物。比较运算符返回 True 或 False。最重要的一点要尽早搞清楚:= 用于赋值,== 用于检查两个值是否相等。混淆它们是最常见的初学者错误之一。
5 > 3 # True
5 < 3 # False
5 == 5 # True (注意:双等号;= 是赋值,== 是比较)
5 != 3 # True ("不等于")
5 >= 5 # True ("大于或等于")
5 <= 4 # False ("小于或等于")= 和 == 的区别几乎让所有人在初期都会犯错。赋值(=)用于存储值;比较(==)用于检查两个值是否相同。
你也可以比较字符串。Python 会按字母顺序比较它们:
"apple" == "apple" # True
"apple" < "banana" # True (a 在 b 前面)
"apple" == "Apple" # False (区分大小写)组合条件
and、or 和 not 用于组合比较。and 要求两边都为真。or 要求至少一边为真。not 会翻转结果。这些可以让你表达现实世界的条件,例如 "分数及格 AND 用户处于活动状态"。
age = 25
score = 88
age >= 18 and score >= 80 # True (两边都必须为真)
age < 18 or score >= 80 # True (至少一边必须为真)
not age >= 18 # False (翻转结果)and 要求两边都为真。or 要求至少一边为真。not 取反。
真值与假值
Python 中的每个值都有布尔解释,即使它不是 True 或 False。空字符串、零、空列表和 None 在条件中都表现得像 False。其他一切都表现得像 True。这意味着 if results: 可以检查列表是否非空,而无需写 if len(results) > 0:。
# 以下这些在条件中都表现得像 False:
False, 0, 0.0, "", [], {}, (), None
# 其他一切都表现得像 True这意味着 if results: 是一种自然的表达方式,用来表示 "如果列表不为空",而 if name: 可以检查字符串是否有任何内容。
if / elif / else
if 语句仅在其条件为 True 时运行一段代码块。elif 在第一个条件为假时添加更多要检查的条件。else 捕获所有未匹配任何条件的情况。Python 使用缩进而不是大括号来定义每个块内的内容。
score = 87
if score >= 90:
print("A grade")
elif score >= 80:
print("B grade")
elif score >= 70:
print("C grade")
else:
print("Below C")规则:
if是必需的,并且总是放在最前面elif("else if" 的缩写)是可选的,可以有任意多个else是可选的,用于处理所有未匹配的情况,并且放在最后- Python 使用缩进(4 个空格)来标记每个块内的内容;没有大括号
缩进不是可选的或装饰性的。Python 使用它来定义结构。不一致的缩进会导致语法错误。
单行条件
对于简单的是/否赋值,Python 有一种紧凑的单行形式,称为三元表达式:value_if_true if condition else value_if_false。仅在逻辑确实简单且读起来像一句话时使用它。
label = "pass" if score >= 50 else "fail"这是一个三元表达式;它读起来像一句话。当逻辑确实简单时使用它。对于涉及 elif 的任何情况,请编写完整版本。
while 循环
只要条件为 True,while 循环就会重复执行其代码块。当你不知道循环应该运行多少次时使用它,例如等待有效输入或重试直到任务成功。
lives = 3
while lives > 0:
print(f"Lives remaining: {lives}")
lives -= 1
print("Game over")当你不知道循环会运行多少次时,while 是最好的。当你知道次数,或者你在迭代一个集合时,for 更简洁。
break 和 continue
break 会立即退出循环,无论还剩多少次迭代。continue 会跳过当前迭代的剩余部分,并跳回到条件检查处。两者都只影响它们所在的最内层循环。
break 会立即退出循环:
target = 5
num = 0
while True:
num += 1
if num == target:
print(f"Found {target}")
break # 停止循环当退出条件复杂或需要在循环体末尾发生时,带有 break 的 while True: 是一种有效且常见的模式。
continue 会跳过当前迭代的剩余部分,并返回到条件检查:
num = 0
while num < 10:
num += 1
if num % 2 == 0:
continue # 跳过偶数
print(num) # 只打印奇数:1, 3, 5, 7, 9for 循环
for 循环每次遍历序列中的一个元素:一个列表、一个字符串、一个数字范围。你在 for 后命名的变量依次接收每个元素。你不需要自己管理计数器或检查长度。
players = ["小明", "小红", "小刚"]
for player in players:
print(f"Hello, {player}!")for 循环也适用于字符串(逐字符迭代)和任何其他序列类型。
range()
range() 生成一个数字序列供你循环。range(5) 会给你 0, 1, 2, 3, 4。你可以控制起始、结束和步长。当你需要循环运行特定次数时使用它。
for i in range(5):
print(i) # 0, 1, 2, 3, 4range() 有三种形式:
| 调用 | 它生成什么 |
|---|---|
range(5) | 0, 1, 2, 3, 4 |
range(2, 6) | 2, 3, 4, 5 |
range(0, 10, 2) | 0, 2, 4, 6, 8(步长为 2) |
range(5, 0, -1) | 5, 4, 3, 2, 1(倒计数) |
range() 不会创建列表。它一次生成一个数字,即使对于非常大的范围也很高效。
enumerate()
enumerate() 在你循环时同时给你索引和值,因此你不需要单独跟踪计数器。i, player 部分在每次迭代时自动接收一对值。
players = ["小明", "小红", "小刚"]
for i, player in enumerate(players):
print(f"{i + 1}. {player}")
# 1. 小明
# 2. 小红
# 3. 小刚i, player 语法称为解包。Python 自动将 (index, value) 对拆分为两个名称。
默认情况下,enumerate() 从 0 开始。传入起始值来改变它:
for i, player in enumerate(players, start=1):
print(f"{i}. {player}") # 从 1 开始嵌套循环
你可以把一个循环放在另一个循环里面。每次外层循环的单次迭代,内层循环都会完整地运行一遍。这就是处理网格、组合或任何具有两级结构的数据的方式。
rows = [1, 2, 3]
cols = ["A", "B"]
for row in rows:
for col in cols:
print(f"{col}{row}", end=" ")
print() # 每行之后换行
# A1 B1
# A2 B2
# A3 B3嵌套循环内部的 break 和 continue 只影响最内层的循环。
循环-else
Python 循环可以有一个 else 子句,它仅在循环未遇到 break 而结束时才运行。它不常用,但它是编写 "在列表中搜索,如果什么也没找到,就执行此操作" 最简洁的方式。
target = "小华"
names = ["小明", "小红", "小刚"]
for name in names:
if name == target:
print(f"Found {target}")
break
else:
print(f"{target} not in list") # 会运行,因为 break 从未触发如果 break 运行了,else 会被跳过。如果循环耗尽了序列,else 会运行。这是一种小众模式,但比标志变量更简洁。
排序
sorted() 返回一个新的排序列表,并保持原始列表不变。.sort() 在原地对列表进行排序并返回 None。key= 参数允许你按原始值以外的内容进行排序。例如,不区分大小写地对名称进行排序,或按分数对玩家元组进行排序。
scores = [87, 42, 96, 55, 71]
ranked = sorted(scores) # [42, 55, 71, 87, 96](新列表)
scores.sort() # 对原始列表排序,返回 None
scores.sort(reverse=True) # [96, 87, 71, 55, 42]两者都接受 key= 参数:在比较之前应用于每个项目的函数:
names = ["小刚", "小明", "小红"]
sorted(names, key=str.lower) # 不区分大小写的排序
players = [("小明", 87), ("小红", 96), ("小刚", 55)]
sorted(players, key=lambda p: p[1]) # 按分数排序什么是 lambda?
lambda p: p[1] 是一个单行函数。它接受一个玩家元组并返回分数。Lambda 函数将在 Lambda、推导式和 zip 一章中介绍。
对于简单情况,使用 sorted()。对于想要原地修改的列表,使用 .sort()。
实践中
遍历分数,累加总分,计算及格数,并打印摘要:
raw_scores = [87, 42, 96, 55, 71, 63]
total = 0
passing = 0
for score in raw_scores:
total += score
if score >= 60:
passing += 1
average = total / len(raw_scores)
print(f"Average: {average:.1f}")
print(f"Passing: {passing}/{len(raw_scores)}")
print(f"Top score: {sorted(raw_scores, reverse=True)[0]}")
