循环控制:break、continue、else

上一篇 循环语句 for 与 while 讲了 for/while 的基础,但真实项目里的循环往往需要动态控制——“某个条件满足时立刻退出”、”这一轮跳过不处理”、”循环正常结束后跑一段收尾”。这就是 break / continue / else 三件套的用武之地。这一篇把它们的语法、语义、惯用法、陷阱一次讲清,特别是 for-else 这个 Python 独有的语法糖,被无数新手忽视,其实很好用。

一、break:立刻退出循环

break 中断最近一层的循环,控制流跳到循环体后的第一条语句:

1
2
3
4
5
# 找出第一个负数
for n in [3, 5, -1, 7, -2]:
if n < 0:
print(f"找到 {n}")
break # 立刻退出,后面 7 和 -2 不再看

break 只跳最近一层,嵌套循环里想跳到最外层需要额外手段(下面讲)。

二、continue:跳过本次迭代

continue 结束本次迭代,直接进入下一轮循环开头(for 会取下一个元素,while 会重新判断条件):

1
2
3
4
5
# 只打印偶数
for n in range(10):
if n % 2 != 0:
continue
print(n)

注意continue 不是 break 的近亲,它不会退出循环,只是跳过剩余的循环体。

continue 与 else if 的区别

1
2
3
4
5
6
7
8
9
10
# 用 continue(Guard 式)
for n in numbers:
if not is_valid(n):
continue
process(n) # 只有合法元素才处理

# 不用 continue
for n in numbers:
if is_valid(n):
process(n)

两种写法功能等价,但当验证逻辑很多时(比如 5 层校验),continue 让代码扁平化:

1
2
3
4
5
6
7
8
9
10
11
12
for order in orders:
if not order.paid:
continue
if order.refunded:
continue
if not order.address:
log("no address")
continue
if order.amount <= 0:
continue
# 到这里说明这是一个可以处理的订单
ship(order)

比嵌套 4 层 if 好读得多。

三、else:循环正常结束后的收尾

for-elsewhile-else 是 Python 特色:当循环因为”迭代完成”而结束(没被 break 打断)时,执行 else 块。

1
2
3
4
5
6
for n in [3, 5, 7, 11]:
if n % 2 == 0:
print("发现偶数")
break
else:
print("全都是奇数") # 只有循环跑完(没 break)才执行

理解要点:else 不是配 if 的,是配 for/while 的。语义可以读成”loop nobreak”—— 循环没被打断时才执行。

常见惯用法:搜索”是否存在”

1
2
3
4
5
6
7
def find(items, target):
for i, x in enumerate(items):
if x == target:
print(f"找到 {target} 在索引 {i}")
break
else:
print(f"{target} 不存在")

for-else 让”未找到”分支非常自然。不用它就得:

1
2
3
4
5
6
7
found = False
for i, x in enumerate(items):
if x == target:
found = True
break
if not found:
print("不存在")

多一个 flag 变量,明显啰嗦。

while-else

while 也支持 else:条件变为假时执行 else(等同”没被 break”)。

1
2
3
4
5
6
7
8
9
attempts = 0
while attempts < 3:
pwd = input("密码:")
if pwd == "123456":
print("登录成功")
break
attempts += 1
else:
print("三次输错,账户已锁定")

四、跳出嵌套循环的四种姿势

break 只跳一层。想跳多层,四种方案:

方案 1:抽成函数 + return(推荐)

1
2
3
4
5
6
7
8
9
def find(matrix, target):
for row in matrix:
for cell in row:
if cell == target:
return True
return False

if find(m, 42):
print("找到")

这是最 Pythonic 的做法。别的方案都是它的降级替代。

方案 2:flag 变量

1
2
3
4
5
6
7
8
found = False
for row in matrix:
for cell in row:
if cell == target:
found = True
break
if found:
break

多层 flag 会越写越乱,慎用。

方案 3:抛异常

1
2
3
4
5
6
7
8
9
10
class _Found(Exception):
pass

try:
for row in matrix:
for cell in row:
if cell == target:
raise _Found
except _Found:
print("找到")

用异常做流控被认为是反模式,除非嵌套非常深,否则不建议。

方案 4:把嵌套改成扁平

itertools.product 或者展开成单层:

1
2
3
from itertools import product
for row, cell in product(matrix, matrix[0]):
...

五、continue 在 while 里的坑

在 while 里用 continue 时,别忘了更新循环变量,否则死循环:

1
2
3
4
5
6
i = 0
while i < 10:
if i == 5:
continue # ❌ i 没变,永远卡在 5!
print(i)
i += 1

正确写法:

1
2
3
4
5
6
7
i = 0
while i < 10:
if i == 5:
i += 1
continue
print(i)
i += 1

for 循环用 continue 就没这个坑,因为迭代器自动”下一步”。所以能用 for 就别用 while。

六、for-else 到底该不该用?

有人觉得 for-else 让代码更简洁,也有人(包括 Guido 本人)承认这个关键字选得不好——else 语义不直观。原本更贴切的名字是 nobreak。用不用这个语法,业界有两派:

  • 鼓励派:写搜索/检查场景时优雅,减少 flag 变量;
  • 保守派:容易被误读为”if-else 的 else”,代码 review 时增加认知负担。

折中建议

  • 团队里所有人都懂 → 大胆用;
  • 有人不熟 → 加一行注释 # 循环没 break
  • 或者干脆抽成函数,用 return 表达”提前找到”。

七、一个综合例子:账户登录

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
# login.py
"""控制台登录模拟,演示循环控制三件套。"""

USERS = {
"admin": "admin888",
"alice": "alice123",
"bob": "bob@2025",
}

MAX_ATTEMPTS = 3


def login() -> bool:
for attempt in range(1, MAX_ATTEMPTS + 1):
user = input(f"用户名(第 {attempt} 次):").strip()
if not user:
print("用户名不能为空")
continue # 空的直接下一轮,不占尝试次数?—— 这里演示占用

if user not in USERS:
print("用户不存在")
continue

pwd = input("密码:")
if pwd == USERS[user]:
print(f"欢迎,{user}")
return True
else:
print(f"密码错误,还剩 {MAX_ATTEMPTS - attempt} 次机会")
else:
# 循环正常跑完(没 return / break)→ 三次都错
print("三次尝试失败,账户已锁定 5 分钟")
return False


def command_loop():
print("输入命令(quit 退出):")
while True:
cmd = input("> ").strip()
if not cmd:
continue # 空行忽略
if cmd in {"quit", "exit"}:
print("再见")
break
if cmd == "help":
print("可用命令:help, status, quit")
continue
print(f"未识别命令 {cmd!r}")


if __name__ == "__main__":
if login():
command_loop()

这段代码里同时用了 break(退出命令循环)、continue(跳过空行/错误用户名)、for-else(三次失败后锁定)、return(登录成功直接跳出函数)。

八、常见陷阱

陷阱 1:break 与 return 混用

在函数里,能用 return 就用 return,比 break 更”干脆”:

1
2
3
4
5
def find(items, target):
for i, x in enumerate(items):
if x == target:
return i # ✅ 直接返回,比 break 后 return 简洁
return -1

陷阱 2:for-else 里没 break

1
2
3
4
for x in items:
print(x)
else:
print("done") # 一定会执行,跟没 else 一样

如果循环里没有 break,else 块是必然执行的,等价于把它写在循环后面——但读代码的人会疑惑”为啥用 else”。没 break 就别写 else

陷阱 3:continue 后写代码

1
2
3
4
5
for x in items:
if x < 0:
continue
print("负数") # 永远执行不到
print(x)

continue 后面的代码是死代码,多数 linter 会警告。

陷阱 4:break 跳不出嵌套函数

1
2
3
4
5
6
def outer():
for x in items:
def inner():
for y in items:
break # 只跳出 inner 的循环,不影响 outer
inner()

break 只在当前函数的最近一层循环生效。

陷阱 5:while True 忘了退出条件

1
2
3
while True:
cmd = input()
print(cmd) # 永远不退出

while True 一定要有 breakreturnraise,否则就是死循环。

九、性能小提示

  • 循环开销:CPython 里循环开销比 C 大得多,能用内置函数就别自己写循环:
    • 累加:sum(nums)for + += 快;
    • 找最大:max(nums)
    • 存在性:any(x > 0 for x in nums)all(x > 0 for x in nums)
    • 一次性构造 list:列表推导式比 append 循环快 30%+。
  • break 早退能避免不必要的工作,尤其是数据量大时。

十、小结与延伸阅读

  • break 退出最近一层循环;
  • continue 跳过本次迭代;
  • else 在循环没被 break 时执行;
  • 嵌套循环退出优先用函数 + return;
  • while + continue 记得手动更新循环变量;
  • 没 break 别写 else;
  • 能用 sum/max/any/all/推导式就别写手工循环。

延伸阅读:

到这里 模块一:Python 基础入门 10 篇 就全部结束了!从下一篇开始进入 模块二:核心数据结构,第一站是 列表 List 详解