第12章 流程控制:循环结构
本章介绍 Python 的两种循环。先讲解 while 循环的适用场景,再讲解 for 循环与可迭代对象的配合,并说明 range()、enumerate() 的常见用法;随后补充嵌套循环与循环的 else 子句,帮助写出结构清晰的重复执行逻辑。
12.1 循环结构
循环用于重复执行一段代码。Python 主要提供 while 和 for 两种循环:
| 循环 | 执行依据 | 适合场景 |
|---|---|---|
while |
某个条件是否仍为真 | 重复次数事先不确定,例如等待合法输入 |
for |
可迭代对象中是否还有下一个元素 | 遍历字符串、列表、range 等对象 |
12.1.1 while 循环
while 循环根据条件的真值决定是否重复执行循环体,适合重复次数事先不确定的场景。
基本语法:
while 条件表达式:
循环体
每轮循环开始前先判断条件;条件为真时执行循环体,完成后再次判断,条件为假时结束循环。
下面使用 while 循环从 1 累加到 100。number += 1 会在每轮中更新计数器,使循环条件最终变为假:
"""使用 while 循环计算 1~100 之和。"""
number = 1
total = 0
while number <= 100:
total += number
number += 1
print(f"1~100 之和:{total}")
运行结果:
1~100 之和:5050
- 如果条件一开始就为假,循环体一次也不会执行。
- 循环体中通常需要更新条件所依赖的状态;如果忘记更新计数器,条件可能始终为真,导致无限循环。
- 有些场景会故意使用
while True创建无限循环,并在满足退出条件时使用break结束循环。 - 真实的常驻服务可以长期运行,但仍应设计清晰的停止条件和资源清理机制。
下面的案例故意使用 while True 持续处理任务,当剩余任务数量变为 0 时,通过 break 结束循环:
"""使用无限循环模拟任务处理。"""
remaining_tasks = 3
while True:
if remaining_tasks == 0:
print("所有任务已完成")
break
# 还有剩余任务,继续处理
print(f"处理任务,剩余:{remaining_tasks}")
remaining_tasks -= 1
运行结果:
处理任务,剩余:3
处理任务,剩余:2
处理任务,剩余:1
所有任务已完成
12.1.2 for 循环
for 循环用于从可迭代对象中逐个取出元素。字符串、列表、元组、字典、集合、range 对象和文件对象等都可以被遍历。
基本语法:
for 元素 in 可迭代对象:
循环体
-
每一轮循环都会把当前元素赋给这个变量,然后执行循环体;当没有更多元素可取时,循环自然结束。
-
遍历字典时默认取出键;如果同时需要键和值,可以遍历
dictionary.items()。 -
如果只是想重复执行固定次数,可以遍历
range();不需要使用循环变量时,通常将其命名为_。"""演示使用 for 循环遍历常见可迭代对象。"""
遍历列表
fruits = ["苹果", "香蕉", "橙子", "葡萄"]
for fruit in fruits:
print(f"水果:{fruit}")遍历字符串
for character in "Python":
print(character, end=" ")print()
同时遍历字典的键和值
scores = {"张三": 86, "李四": 92, "王五": 78}
for name, score in scores.items():
print(f"{name}:{score} 分")重复执行固定次数,但不使用循环变量
for _ in range(3):
print("重复执行")
12.1.3 使用 range() 生成整数序列
range() 创建一个不可变的、可迭代的整数序列对象,并不会事先把所有整数存入列表。它有三种常用形式:
range(stop)
range(start, stop)
range(start, stop, step)
| 参数 | 作用 | 默认值 |
|---|---|---|
start |
起始值,包含在结果中 | 0 |
stop |
停止值,不包含在结果中 | 无,必填 |
step |
步长,可以为正数或负数,但不能为 0 | 1 |
下面使用 list() 将 range 转换为列表,便于直观查看其中的整数:
"""演示 range() 的起始值、停止值和步长。"""
print(list(range(5))) # [0, 1, 2, 3, 4]
print(list(range(2, 6))) # [2, 3, 4, 5]
print(list(range(2, 10, 3))) # [2, 5, 8]
print(list(range(9, 0, -2))) # [9, 7, 5, 3, 1]
print(list(range(1, 5, -1))) # []
# 步长为 0 会触发 ValueError
# print(list(range(1, 5, 0)))
range() 遵循"包含起始值,不包含停止值"的规则。正步长时,起始值应小于停止值;负步长时,起始值应大于停止值,否则会得到空序列。
12.1.4 使用 enumerate() 获取编号与元素
遍历序列时,如果同时需要位置编号和元素,可以使用 enumerate()。它比手动维护计数器更简洁,也更不容出现编号更新错误。
"""借助 enumerate 函数给元素编号。"""
frameworks = ["Django", "Flask", "FastAPI"]
for sequence_number, framework in enumerate(frameworks, start=1):
print(f"{sequence_number}. {framework}")
运行结果:
1. Django
2. Flask
3. FastAPI
start=1 只改变生成的编号起点,不会修改原序列的索引。
12.1.5 嵌套循环
在一个循环的循环体中继续使用另一个循环,就形成了嵌套循环。外层循环每执行一轮,内层循环通常会完整执行一遍。
下面使用嵌套循环输出教室座位表:
"""使用嵌套循环输出座位表。"""
for row in range(1, 4):
for seat in range(1, 5):
print(f"{row}排{seat}座", end=" ")
print()
当 row 等于 2 时,内层的 seat 依次取 1 到 4,输出 4 个座位编号。内层循环结束后,不带参数的 print() 输出换行,然后外层循环进入下一轮。
嵌套循环的执行次数会相乘。例如,外层和内层都执行 1000 次时,内部语句可能执行约 100 万次。处理大量数据时,应关注不必要的多层遍历。
12.1.6 循环的 else 子句
while 和 for 都可以带有 else 子句。else 不是在"循环条件为假的每一次"执行,而是在循环正常结束时执行。
循环 else 常用于"搜索成功就提前结束,遍历完仍未找到就执行备选处理"的场景:
"""使用 for...else 搜索用户。"""
usernames = ["alice", "bob", "carol"]
target = "bob"
for username in usernames:
if username == target:
print(f"找到用户:{target}")
break
# 循环全部走完后执行 else
else:
notice = f"未找到用户:{target}"
print(notice)
当 target 为 "bob" 时,循环找到目标并通过 break 结束,因此不执行 else。如果将目标改为不存在的用户,循环会自然遍历完毕,此时执行 else。
while因条件变为假而自然结束时,执行else;for将可迭代对象遍历完毕时,执行else;- 循环通过
break结束时,跳过else; continue只跳过当前轮次,不会阻止循环正常结束后执行else;- 如果循环体一次都没有执行,只要不是由
break结束,else仍会执行。
如果循环所在函数通过 return 提前返回,或循环因异常中断,执行流已经离开循环结构,对应的 else 也不会执行。在常见代码中,可以把循环 else 简单理解为"循环没有遇到 break 并顺利遍历完毕后执行"。