飞翔飞翔
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
主页
  • 计算机基础

    • TCP/IP协议
    • Linux命令
  • 数据库

    • SQL教程
  • 编程语言

    • C语言
    • Python2
    • Python3
  • 数据格式

    • JSON教程
  • 工具

    • Markdown指南
  • Git

    • GitFlow
  • Quartz

    • Quartz教程
  • Java

    • Java设计模式
  • 缓存

    • Redis教程
联系
阿里云
  • 学习路径
  • 第1章 Python简介

    • Python是什么
    • 安装与运行
    • 交互式解释器
    • 注释与编码规范
  • 第2章 变量与数据类型

    • 变量与对象
    • 整数 int
    • 浮点数 float
    • 复数 complex
    • 布尔值 bool
    • 字符串 str
    • 空值 None
    • 类型转换
  • 第3章 运算符与表达式

    • 算术运算符
    • 比较运算符
    • 赋值运算符
    • 逻辑运算符
    • 位运算符
    • 身份与成员运算符
    • 海象运算符
    • 运算符优先级
  • 第4章 流程控制

    • if 语句
    • if-else 语句
    • if-elif-else 语句
    • match-case 语句
    • 条件表达式(三元运算符)
    • while 循环
    • for 循环
    • range 函数
    • break 与 continue
    • 循环的 else 子句
    • pass 语句
  • 第5章 数据结构

    • 列表创建与索引
    • 列表方法
    • 列表推导式
    • 元组
    • 序列解包
    • 集合
    • 字典创建与访问
    • 字典方法
    • 字典推导式
    • range 对象
  • 第6章 函数

    • 定义函数
    • 位置参数与关键字参数
    • 默认参数
    • 可变参数
    • 解包实参
    • 函数返回值
    • lambda 表达式
    • 文档字符串与注解
    • 作用域与命名空间
    • global 与 nonlocal
  • 第7章 模块与包

    • 模块导入
    • 模块搜索路径
    • 包与相对导入
    • 标准库概览
  • 第8章 文件与输入输出

    • 文件读写
    • 上下文管理器
    • 字符串格式化
    • JSON 与 CSV
  • 第9章 面向对象

    • 类与对象
    • 方法
    • 实例变量与类变量
    • 私有变量
    • 继承
    • 多重继承
    • 魔术方法
    • 属性装饰器
    • 数据类 dataclass
  • 第10章 异常处理

    • 语法错误与异常
    • try-except
    • 异常链与 raise
    • 清理操作
    • 自定义异常
  • 第11章 迭代器与生成器

    • 迭代器协议
    • 生成器
    • 生成器表达式
    • 迭代工具
  • 第12章 高级特性

    • 装饰器
    • 函数式编程
  • 第13章 工程实践

    • 测试与调试
    • 代码质量
    • 虚拟环境

循环的 else 子句

Python 的 for 和 while 循环支持一个不太常见但非常有用的 else 子句。它的行为与 if 语句中的 else 截然不同:循环的 else 在循环正常结束时执行,如果循环被 break 提前终止,则 else 不会执行。

基本语义

for-else

在 for 循环中,else 子句在序列迭代完毕、未触发 break 的情况下执行:

for i in range(3):
    print(i)
else:
    print("循环正常结束")

输出:

0
1
2
循环正常结束

如果加入 break:

for i in range(3):
    print(i)
    if i == 1:
        break
else:
    print("这不会执行")

输出 0、1 后,break 终止循环,else 子句被跳过。

while-else

在 while 循环中,else 在循环条件变为假值后执行,同样要求循环未被 break 打断:

count = 3
while count > 0:
    print(count)
    count -= 1
else:
    print("倒计时结束")

输出:

3
2
1
倒计时结束

与 break 的关系

循环 else 的核心设计意图是配合 break 实现搜索逻辑:当循环的目的是查找某个东西时,break 表示"找到了",而 else 表示"找遍了但没找到"。

Python 官方教程用搜索质数的例子完美展示了这一点:

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(f"{n} = {x} * {n//x}")
            break
    else:
        # 循环到底未找到一个因数
        print(f"{n} 是质数")

输出:

2 是质数
3 是质数
4 = 2 * 2
5 是质数
6 = 2 * 3
7 是质数
8 = 2 * 4
9 = 3 * 3

注意 else 的缩进层级与内层 for 对齐,而非与 if 对齐。当内层循环遍历所有可能的因数而未触发 break 时,else 执行,确认该数字为质数。

常见误解

循环 else 是 Python 最容易被误解的特性之一,主要源于它与 if-else 的表面相似性。

误解一:else 属于 if

初学者常误以为 else 与前面的 if 配对:

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(f"{n} 是合数")
            break
        else:
            print(f"{n} 是质数")  # 错误理解!

如果 else 属于 if,那么每个不满足 n % x == 0 的 x 都会打印一次质数,导致大量重复输出。实际上 else 属于 for,只在整个循环结束后执行一次。

误解二:else 表示"循环失败"

有人觉得 else 应该在循环出错时执行。恰恰相反,else 表示循环成功完成了全部迭代,类似于 try 语句的 else(未发生异常时执行)。官方文档明确指出:"当配合循环使用时,else 子句更像是 try 语句的 else 子句而不像 if 语句的相应子句。"

误解三:else 在循环体执行零次时跳过

for item in []:
    print("不会执行")
else:
    print("仍然会执行")  # 会执行

即使循环体一次都没执行,else 也会执行,因为循环"正常结束"了——它没有被 break 打断。

其他提前结束方式

除了 break,以下方式提前结束循环也会跳过 else:

  • return(在函数内)
  • 引发异常(未被捕获)
def search(items, target):
    for item in items:
        if item == target:
            return "找到"
    else:
        return "未找到"

print(search([1, 2, 3], 2))  # 找到
print(search([1, 2, 3], 5))  # 未找到

return 直接退出函数,循环的 else 不会执行。上面的代码中,else 只在未找到目标时执行,逻辑清晰。

实际应用场景

线性搜索:

def find_index(items, target):
    for i, item in enumerate(items):
        if item == target:
            print(f"在索引 {i} 处找到")
            break
    else:
        print("未找到目标")

find_index(["a", "b", "c"], "b")  # 在索引 1 处找到
find_index(["a", "b", "c"], "z")  # 未找到目标

验证全部通过:

scores = [85, 92, 78, 88]

for s in scores:
    if s < 60:
        print("存在不及格成绩")
        break
else:
    print("所有成绩均合格")

密码尝试限制:

max_attempts = 3
attempts = 0

while attempts < max_attempts:
    pwd = input("请输入密码:")
    if pwd == "secret":
        print("登录成功")
        break
    attempts += 1
    print(f"密码错误,还剩 {max_attempts - attempts} 次机会")
else:
    print("尝试次数耗尽,账户已锁定")

是否必须使用 else

循环 else 完全可选。对于不习惯这一特性的开发者,用标志变量也能实现相同逻辑:

found = False
for item in items:
    if item == target:
        found = True
        break

if not found:
    print("未找到")

但 else 子句将"搜索"和"未找到"的逻辑绑定在同一语法结构中,减少了临时变量,使意图更加明确。一旦熟悉其语义,循环 else 能让搜索类代码更加紧凑和可读。

理解循环 else 的关键在于记住:它对应的是循环的正常完成,而非条件的否定。把它想象成 try 的 else(未发生异常)而非 if 的 else(条件为假),就能避免绝大多数困惑。

上一页
break 与 continue
下一页
pass 语句