Skip to content

03-流程控制

本章代码基于 Python 3.11+ 编写

流程控制让程序能够根据条件做出决策和重复执行任务。本章重点介绍 Python 3.10+ 新增的 match 语句。


本章讲解条件语句和循环语句,控制程序的执行流程。


概念铺垫

为什么需要流程控制?一个真实的决策场景

问题场景: 你在开发一个自动售货机程序,需要根据用户投入金额决定可以购买的饮料。

不使用流程控制的困惑:

  • 程序只能"直线执行",无法根据条件做出不同反应
  • 如何处理"如果...就...否则..."的情况?

使用流程控制的解决方案:

python
# 自动售货机决策
money: float = 4.0

# 使用 if 判断
if money >= 5:
    print("可以购买可乐(5元)")
elif money >= 4:
    print("可以购买雪碧(4元)")
elif money >= 3:
    print("可以购买矿泉水(3元)")
else:
    print("金额不足,请继续投币")

这就是流程控制的价值:让程序能够根据条件做出决策


流程控制解决了什么问题?

流程控制的本质是:让程序能够根据条件做出不同的反应

就像你早上出门前的决策:

  • 如果下雨 → 带伞
  • 如果不下雨 → 不带伞

流程控制的类型:

  1. 分支(if):根据条件选择不同路径
  2. 循环(for/while):重复执行相同操作
  3. 模式匹配(match):根据数据结构选择处理方式(Python 3.10+)

流程控制的最简用法(5分钟上手)

最简单的 if 语句:

python
age: int = 18

if age >= 18:
    print("成年人")
else:
    print("未成年人")

最简单的 for 循环:

python
# 打印1到5
for i in range(1, 6):
    print(i)

最简单的 match 语句(Python 3.10+):

python
status: str = "success"

match status:
    case "success":
        print("操作成功")
    case "error":
        print("操作失败")
    case _:
        print("未知状态")

这就是流程控制的基本用法。接下来我们详细学习更多功能。


什么是流程控制

流程控制(Control Flow) 决定程序中代码的执行顺序。

┌─────────────────────────────────────────┐
│         Python 流程控制类型              │
├─────────────────────────────────────────┤
│                                         │
│  1. 条件分支(选择结构)                │
│     • if 语句                           │
│     • if-else 语句                      │
│     • if-elif-else 语句                 │
│                                         │
│  2. 循环结构(重复执行)                │
│     • for 循环                          │
│     • while 循环                        │
│                                         │
│  3. 循环控制                            │
│     • break(跳出循环)                 │
│     • continue(跳过本次)              │
│                                         │
└─────────────────────────────────────────┘

L1 理解层:会用

if 语句

基本语法

┌─────────────────────────────────────────┐
│            if 语句语法                   │
├─────────────────────────────────────────┤
│                                         │
│   if 条件:                               │
│       条件成立时执行的代码             │
│                                         │
│   语法要点:                            │
│   • 条件 → 返回 True 或 False           │
│   • :   → 冒号,不能省略!              │
│   • 缩进 → 代码块必须缩进(4 空格)     │
│                                         │
└─────────────────────────────────────────┘

示例

python
# 判断是否为正数
number = 5

if number > 0:
    print(f"{number} 是正数")

if-else 语句

基本语法

┌─────────────────────────────────────────┐
│          if-else 语句语法                │
├─────────────────────────────────────────┤
│                                         │
│   if 条件:                               │
│       条件成立时执行                    │
│   else:                                  │
│       条件不成立时执行                  │
│                                         │
└─────────────────────────────────────────┘

示例

python
# 判断奇偶数
number = 7

if number % 2 == 0:
    print(f"{number} 是偶数")
else:
    print(f"{number} 是奇数")

if-elif-else 语句

基本语法

┌─────────────────────────────────────────┐
│       if-elif-else 语句语法              │
├─────────────────────────────────────────┤
│                                         │
│   if 条件 1:                             │
│       条件 1 成立时执行                  │
│   elif 条件 2:                           │
│       条件 2 成立时执行                  │
│   else:                                  │
│       以上都不成立时执行                │
│                                         │
│   注意:一旦某个条件满足,立即退出      │
│                                         │
└─────────────────────────────────────────┘

示例:成绩等级

python
score = 85

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:
    grade = "F"

print(f"等级:{grade}")  # 输出:等级:B

pass 语句(占位符)

什么是 pass

pass 是一个占位语句,不执行任何操作。当语法上需要语句但不需要执行任何代码时使用。

┌─────────────────────────────────────────┐
│              pass 的作用                 │
├─────────────────────────────────────────┤
│                                         │
│  • 占位:先占个位置,以后再写代码       │
│  • 空块:保持语法完整性                 │
│  • 跳过:暂时跳过某些条件               │
│                                         │
│  pass 执行时:什么都不做,直接跳过      │
│                                         │
└─────────────────────────────────────────┘

为什么需要 pass

问题:Python 不允许空代码块

python
# ❌ 错误:if 后面不能是空的
if True:
    # 语法错误!Expected an indented block

# ✅ 正确:使用 pass 占位
if True:
    pass  # 暂时什么都不做

实际场景

场景1:函数占位(开发中)

python
def calculate_tax(income: float) -> float:
    """计算税费(待实现)"""
    pass  # TODO: 稍后实现


def process_data(data: list) -> None:
    """处理数据(待实现)"""
    pass  # TODO: 稍后实现


# 代码可以正常运行
calculate_tax(5000)  # 不会报错
process_data([1, 2, 3])

场景2:类定义占位

python
class User:
    """用户类(待实现)"""
    pass  # 先定义类名,稍后添加属性和方法


class Database:
    pass


# 可以创建实例
user = User()
db = Database()

场景3:条件分支占位

python
status: str = "pending"

if status == "approved":
    process_order()
elif status == "rejected":
    notify_user()
elif status == "pending":
    pass  # 待处理状态,暂不操作
else:
    handle_unknown()

场景4:循环体占位

python
# 读取文件直到结束
with open("data.txt") as f:
    for line in f:
        pass  # 只读取,不处理

# 或者等待某个条件
while not ready:
    pass  # 等待中...

pass vs ... (Ellipsis)

Python 中还有一个类似的占位符:...(三个点,Ellipsis)

python
# pass 和 ... 都可以用于占位
def func1():
    pass  # 传统写法


def func2():
    ...  # Python 3 新写法(更简洁)


# 两者效果相同
# ... 在类型提示和切片中也有其他用途

推荐: 在代码占位时使用 pass 更明确。

常见用法总结

┌─────────────────────────────────────────────────────┐
│              pass 常见用法                           │
├─────────────────────────────────────────────────────┤
│                                                     │
│  1. 函数/方法占位(待实现)                         │
│     def my_func():                                 │
│         pass                                       │
│                                                     │
│  2. 类定义占位                                      │
│     class MyClass:                                 │
│         pass                                       │
│                                                     │
│  3. 条件分支占位                                    │
│     if condition:                                  │
│         pass  # 暂不处理                           │
│                                                     │
│  4. 异常处理占位                                    │
│     try:                                           │
│         risky_operation()                          │
│     except ValueError:                             │
│         pass  # 忽略这个错误                       │
│                                                     │
└─────────────────────────────────────────────────────┘

三元运算符

概念说明

三元运算符(又称三元表达式)是简化版的 if-else 语句,用于在一行内根据条件选择值。它是 Python 中唯一的条件表达式。

为什么需要三元运算符?

  • 简化代码:将简单的 if-else 压缩成一行
  • 提高可读性:适合赋值场景,一眼就能看清"条件→结果"
  • 函数式风格:常用于 Lambda、列表推导等场景

语法特点:

  • Python 的三元运算符语法与 C/Java 不同
  • 顺序是"结果在前,条件在后":值1 if 条件 else 值2
  • 不支持 elif,只处理两种情况

基本语法

┌─────────────────────────────────────────────────────┐
│            三元运算符语法                            │
├─────────────────────────────────────────────────────┤
│                                                     │
│   值 1 if 条件 else 值 2                             │
│                                                     │
│   执行逻辑:                                        │
│   • 条件为 True  → 返回值 1                         │
│   • 条件为 False → 返回值 2                         │
│                                                     │
│   与其他语言对比:                                  │
│   C/Java:   条件 ? 值1 : 值2                        │
│   Python:   值1 if 条件 else 值2                    │
│                                                     │
│   Python 的写法更像自然语言:                       │
│   "成年 如果 年龄>=18 否则 未成年"                  │
│                                                     │
└─────────────────────────────────────────────────────┘

示例代码

示例 1:基础用法

python
# 传统 if-else 写法(4行)
age = 20
if age >= 18:
    status = "成年"
else:
    status = "未成年"

# 三元运算符写法(1行)
status = "成年" if age >= 18 else "未成年"
print(status)  # 成年

示例 2:用于变量赋值

python
# 根据分数判断是否通过
score: int = 75
result: str = "通过" if score >= 60 else "不及格"
print(result)  # 通过

# 根据温度选择衣物
temperature: int = 28
clothing: str = "短袖" if temperature > 25 else "外套"
print(clothing)  # 短袖

示例 3:用于函数返回值

python
def get_sign(number: int) -> str:
    """返回数字的正负符号"""
    return "正数" if number > 0 else "负数或零"

print(get_sign(10))   # 正数
print(get_sign(-5))   # 负数或零


def get_max(a: int, b: int) -> int:
    """返回较大值(简化版)"""
    return a if a > b else b

print(get_max(3, 5))  # 5

示例 4:用于列表推导

python
# 筛选并标记
scores: list[int] = [85, 45, 92, 58, 78]
labels: list[str] = ["通过" if s >= 60 else "不及格" for s in scores]
print(labels)  # ['通过', '不及格', '通过', '不及格', '通过']

# 将负数转为 0
numbers: list[int] = [-3, 5, -1, 8, 0]
normalized: list[int] = [n if n > 0 else 0 for n in numbers]
print(normalized)  # [0, 5, 0, 8, 0]

关键代码解释:

代码片段读法含义
"通过" if s >= 60 else "不及格"如果分数 ≥ 60 取"通过",否则取"不及格"三元表达式作为列表元素
[... for s in scores]对 scores 每个元素 s 执行前面的表达式列表推导式遍历 scores
[n if n > 0 else 0 for n in numbers]正数保留,负数/零替换为 0三元 + 推导组合:先判断再收集

示例 5:用于 Lambda 函数

python
# Lambda 中不能使用 if-else 语句,但可以用三元表达式
is_even: callable = lambda x: "偶数" if x % 2 == 0 else "奇数"
print(is_even(4))  # 偶数
print(is_even(7))  # 奇数

# 条件计算
safe_divide: callable = lambda a, b: a / b if b != 0 else 0
print(safe_divide(10, 2))  # 5.0
print(safe_divide(10, 0))  # 0

关键代码解释:

代码片段含义为什么用三元而不是 if-else
lambda x: "偶数" if x % 2 == 0 else "奇数"匿名函数:输入 x,返回奇偶判断字符串lambda 体只能是表达式,不能用语句(if-else 是语句)
lambda a, b: a / b if b != 0 else 0安全除法:除数不为 0 才做除法,否则返回 0三元表达式防止除零错误(ZeroDivisionError)

嵌套三元运算符

三元运算符可以嵌套,但要注意可读性:

python
# 嵌套三元运算符(多层条件)
score: int = 85
grade: str = "A" if score >= 90 else ("B" if score >= 80 else "C")
print(grade)  # B

# 嵌套过多时,建议改用 if-elif-else
# 更清晰的写法:
if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
else:
    grade = "C"

可读性建议:

  • 单层三元运算符:推荐使用,简洁清晰
  • 双层嵌套:可接受,但需要括号明确优先级
  • 三层及以上:不推荐,改用 if-elif-else

三元运算符 vs if-else 对比

┌─────────────────────────────────────────────────────┐
│         三元运算符 vs if-else 对比                   │
├─────────────────────────────────────────────────────┤
│                                                     │
│  特性          三元运算符         if-else           │
│  ──────        ────────           ──────            │
│  适用场景      简单二选一赋值     复杂多分支逻辑      │
│  代码行数      1 行              4+ 行              │
│  可读性        简单时更高         复杂时更高          │
│  功能          只支持两种结果     支持多分支          │
│  嵌套能力      可嵌套但不推荐     自由嵌套            │
│                                                     │
│  选择建议:                                          │
│  • 简单赋值 → 三元运算符                            │
│  • 多分支判断 → if-elif-else                        │
│  • 函数式场景(Lambda/推导)→ 三元运算符             │
│                                                     │
└─────────────────────────────────────────────────────┘

match 语句(Python 3.10+)

概念说明

match 语句 是 Python 3.10 引入的新特性,用于模式匹配,可以替代复杂的 if-elif 链。

┌─────────────────────────────────────────┐
│         match 语句优势                   │
├─────────────────────────────────────────┤
│                                         │
│  ✅ 代码更清晰易读                      │
│  ✅ 支持结构模式匹配                    │
│  ✅ 支持解构复杂数据                    │
│  ✅ 减少条件判断嵌套                    │
│                                         │
└─────────────────────────────────────────┘

基础用法

python
# 替代复杂的 if-elif chain
status: str = "success"

match status:
    case "success":
        print("操作成功")
    case "error":
        print("操作失败")
    case "pending":
        print("处理中")
    case _:
        print("未知状态")  # _ 是通配符

高级用法:结构模式匹配

python
# 匹配数据结构
def process_command(cmd: dict[str, str]) -> str:
    match cmd:
        case {"action": "move", "direction": d}:
            return f"向{d}移动"
        case {"action": "attack", "target": t}:
            return f"攻击{t}"
        case {"action": "quit"}:
            return "退出游戏"
        case _:
            return "未知命令"

# 使用示例
cmd1: dict[str, str] = {"action": "move", "direction": "北"}
print(process_command(cmd1))  # 输出:向北移动

cmd2: dict[str, str] = {"action": "attack", "target": "怪物"}
print(process_command(cmd2))  # 输出:攻击怪物

关键代码解释:

代码含义说明
case {"action": "move", "direction": d}:匹配包含 action="move" 的字典,并将 direction 的值绑定到变量 dd 是捕获变量,自动提取字典中对应键的值
case {"action": "attack", "target": t}:匹配 action="attack",并捕获 target 的值到 t不同 case 可以捕获不同的字段
case _:通配符,匹配所有未被前面 case 匹配的情况相当于 else,避免遗漏处理

匹配多个值

python
# 使用 | 匹配多个值
grade: str = "B"

match grade:
    case "A" | "A+":
        print("优秀")
    case "B" | "B+":
        print("良好")
    case "C":
        print("中等")
    case _:
        print("需要努力")

匹配序列

python
# 匹配列表结构
def analyze_list(items: list[int]) -> str:
    match items:
        case []:
            return "空列表"
        case [x]:
            return f"单元素:{x}"
        case [x, y]:
            return f"两个元素:{x}{y}"
        case [first, *rest]:
            return f"首元素:{first}, 其余:{rest}"
        case _:
            return "未知结构"

print(analyze_list([]))           # 空列表
print(analyze_list([1]))          # 单元素:1
print(analyze_list([1, 2, 3, 4])) # 首元素:1, 其余:[2, 3, 4]

match vs if-elif 对比

┌─────────────────────────────────────────────────────┐
│         match vs if-elif 对比                        │
├─────────────────────────────────────────────────────┤
│                                                     │
│  特性          if-elif         match                │
│  ──────        ───────         ─────                │
│  适用场景      简单条件判断     模式匹配、结构解构    │
│  代码可读性    条件多时较复杂   结构清晰              │
│  功能          基础判断         高级模式匹配          │
│  版本要求      所有版本         Python 3.10+        │
│                                                     │
│  选择建议:                                          │
│  • 简单条件判断 → if-elif                           │
│  • 多分支等值判断 → match                           │
│  • 解构数据结构 → match                             │
│                                                     │
└─────────────────────────────────────────────────────┘

for 循环

基本语法

┌─────────────────────────────────────────┐
│            for 循环语法                  │
├─────────────────────────────────────────┤
│                                         │
│   for 变量 in 可迭代对象:                │
│       循环体                             │
│                                         │
└─────────────────────────────────────────┘

示例:遍历列表

python
fruits = ["apple", "banana", "orange"]

for fruit in fruits:
    print(fruit)

# 输出:
# apple
# banana
# orange

range() 函数

三种用法

┌─────────────────────────────────────────┐
│          range() 函数用法                │
├─────────────────────────────────────────┤
│                                         │
│  1. range(stop)                         │
│     生成 0 到 stop-1 的数字              │
│     range(5) → 0, 1, 2, 3, 4           │
│                                         │
│  2. range(start, stop)                  │
│     生成 start 到 stop-1 的数字          │
│     range(2, 5) → 2, 3, 4              │
│                                         │
│  3. range(start, stop, step)            │
│     生成 start 到 stop-1,步长为 step   │
│     range(0, 10, 2) → 0, 2, 4, 6, 8   │
│                                         │
│  注意:包头不包尾                        │
│                                         │
└─────────────────────────────────────────┘

示例

python
# 计算 1+2+3+...+100
total = 0
for i in range(1, 101):
    total += i
print(total)  # 5050

# 倒序循环
for i in range(5, 0, -1):
    print(i, end=" ")
# 输出:5 4 3 2 1

while 循环

基本语法

┌─────────────────────────────────────────┐
│          while 循环语法                  │
├─────────────────────────────────────────┤
│                                         │
│   while 条件:                            │
│       循环体                             │
│                                         │
│   ⚠️ 必须在循环体内修改条件,          │
│   否则会变成无限循环!                  │
│                                         │
└─────────────────────────────────────────┘

示例

python
# 从 1 数到 5
count = 1
while count <= 5:
    print(count)
    count += 1

# 输出:1 2 3 4 5

break 和 continue

break:跳出整个循环

python
# 找到第一个能被 7 整除的数
for i in range(1, 101):
    if i % 7 == 0:
        print(f"找到了:{i}")
        break

# 输出:找到了:7

continue:跳过本次循环

python
# 只打印奇数
for i in range(1, 11):
    if i % 2 == 0:
        continue
    print(i, end=" ")

# 输出:1 3 5 7 9

对比

break:                    continue:

i=1 → 打印 1               i=1 → 打印 1
i=2 → 打印 2               i=2 → 打印 2
i=3 → break → 退出        i=3 → continue → 跳过
         ⨯ 不打印              i=4 → 打印 4
         ⨯ 不打印              i=5 → 打印 5

循环的 else 子句

python
# 循环正常结束时执行 else
for i in range(5):
    print(i)
else:
    print("循环正常结束")

# 被 break 打断时不执行 else
for i in range(5):
    if i == 3:
        break
    print(i)
else:
    print("这句话不会打印")

从简单到复杂:流程控制的渐进应用

层级1:单一条件

python
# 简单 if
age: int = 18
if age >= 18:
    print("成年人")

层级2:多条件判断

python
# if-elif-else
score: int = 85
if score >= 90:
    print("优秀")
elif score >= 60:
    print("通过")
else:
    print("不及格")

层级3:嵌套条件

python
# 嵌套 if
score: int = 85
has_bonus: bool = True

if score >= 60:
    if has_bonus:
        print("通过 + 加分")
    else:
        print("通过")

层级4:循环 + 条件

python
# 筛选数据
scores: list[int] = [85, 45, 92, 58, 78]
passed: list[int] = []

for score in scores:
    if score >= 60:
        passed.append(score)

print(f"通过人数:{len(passed)}")

层级5:match 语句应用

python
# 使用 match 简化判断(Python 3.10+)
action: str = "attack"

match action:
    case "move":
        print("移动")
    case "attack":
        print("攻击")
    case "defend":
        print("防御")
    case _:
        print("未知动作")

综合应用:自动售货机模拟程序

这个示例综合运用流程控制的多个知识点:

python
# 自动售货机程序(Python 3.11+)
def vending_machine() -> None:
    """自动售货机模拟程序"""
    print("=== 自动售货机 ===")
    print("可乐:5元 | 矿泉水:3元 | 雪碧:4元")
    
    balance: float = 0.0
    
    while True:
        print(f"当前余额:{balance:.1f}元")
        
        action: str = input("投币(I) / 购买(B) / 退出(Q): ").upper()
        
        match action:
            case "I":
                coin: float = float(input("投入金额:"))
                balance += coin
            case "B":
                drink: str = input("选择饮料(可乐/矿泉水/雪碧):")
                
                price_map: dict[str, float] = {
                    "可乐": 5.0, 
                    "矿泉水": 3.0, 
                    "雪碧": 4.0
                }
                price: float = price_map.get(drink, 0.0)
                
                if balance >= price:
                    balance -= price
                    print(f"购买成功!剩余余额:{balance:.1f}元")
                else:
                    print(f"余额不足!{drink}需要{price}元")
            case "Q":
                print(f"退出,返还余额:{balance:.1f}元")
                break
            case _:
                print("无效操作")

if __name__ == "__main__":
    vending_machine()

这个程序展示了:

  • if/elif 判断条件
  • while 循环持续运行
  • match 语句处理用户输入
  • 循环与条件的组合使用
  • break 跳出循环

关键代码说明:

代码含义为什么这样写
while True:无限循环,程序持续等待用户操作售货机需要反复响应,直到用户主动退出
input(...).upper()获取输入后立即转大写让用户输入 i/I 都能识别,不区分大小写
match action: case "I":根据用户操作分支执行match 比 if-elif 链更清晰,每个 case 独立
price_map.get(drink, 0.0)安全查找饮料价格,不存在则返回 0.0避免用户输入不存在的饮料时 KeyError 崩溃
balance += coin复合赋值:余额加上投入金额+= 等价于 balance = balance + coin,更简洁
break退出 while 循环Q 操作后用 break 结束无限循环

L2 实践层:用好

推荐做法

做法原因示例
用守卫子句(guard clause)替代深层嵌套减少缩进层级,提高可读性if not valid: return
简单二选一赋值用三元运算符一行表达,语义清晰"通过" if s >= 60 else "不及格"
多分支等值判断用 match(3.10+)语法清晰,支持结构化匹配match status: case "ok": ...
遍历序列用 for,条件循环用 while各司其职,语义准确for item in items:
for 优先于 while(有明确范围时)避免忘更条件导致死循环for i in range(10):
提前 break 替代 while 条件累积减少循环条件复杂度while True: if done: break
for-else 用于"搜索未找到"模式比标志变量更优雅for x in items: if found: break else: not_found()
pass 而非空注释占位语义明确,编辑器友好def todo(): pass

反模式:不要这样做

python
# ❌ 错误:深层嵌套(箭头代码)
def process(data):
    if data:
        if data.valid:
            if data.has_permission:
                if data.is_ready:
                    return do_work(data)
    return None

# ✅ 正确:用守卫子句扁平化
def process(data):
    if not data:
        return None
    if not data.valid:
        return None
    if not data.has_permission:
        return None
    if not data.is_ready:
        return None
    return do_work(data)
python
# ❌ 错误:简单等值判断使用 if-elif 链
if status == "success":
    ...
elif status == "error":
    ...
elif status == "pending":
    ...
else:
    ...

# ✅ 正确:用 match(Python 3.10+)
match status:
    case "success":
        ...
    case "error":
        ...
    case "pending":
        ...
    case _:
        ...
python
# ❌ 错误:滥用三元运算符导致难读
result = "A" if s > 90 else "B" if s > 80 else "C" if s > 70 else "D" if s > 60 else "F"

# ✅ 正确:多档判断用 if-elif-else
if s > 90:
    result = "A"
elif s > 80:
    result = "B"
elif s > 70:
    result = "C"
elif s > 60:
    result = "D"
else:
    result = "F"
python
# ❌ 错误:for 循环中使用 else 后没有注释说明意图
for item in items:
    if item == target:
        break
else:
    print("未找到")  # 新手看不懂 else 的含义

# ✅ 正确:在 else 附近加注释,或改用标志变量
found = False
for item in items:
    if item == target:
        found = True
        break
if not found:
    print("未找到")
python
# ❌ 错误:用 while 遍历已知序列
i = 0
while i < len(items):
    print(items[i])
    i += 1

# ✅ 正确:用 for 循环
for item in items:
    print(item)

常见陷阱

陷阱说明解决方案
缩进混用 Tab 和空格Python 3 不允许混用统一使用 4 空格缩进
= vs == 混淆赋值和比较符号不同条件中只写 ==,不写 =
while 忘更条件导致无限循环while True + break 模式,或确保条件会被修改
for-else 语义误解else 在 break 后不执行,新手易困惑谨慎使用,必要时加注释
match 通配符 _ vs 变量case _: 是通配符,case x: 会绑定变量注意 _ 的特殊语义
列表遍历中修改列表for item in items: items.remove(item) 会跳过元素遍历副本 for item in items[:]:
可变对象作循环变量在循环中修改列表元素影响后续迭代使用不可变对象或确保不会副作用

适用场景

场景是否推荐原因
简单条件判断✅ if-else最基础的流程控制
多条件、互斥分支✅ if-elif-else语义清晰,顺序判断
多分支等值匹配✅ match(3.10+)模式匹配更强大
已知次数/范围循环✅ for + range()安全,不会死循环
条件未知、动态循环✅ while灵活,适合不确定迭代次数
函数参数校验✅ 守卫子句 + 提前返回减少嵌套
简单二选一赋值✅ 三元运算符一行解决
多层条件赋值❌ 嵌套三元改用 if-elif-else
搜索特定元素✅ for + break + elsePython 特有的优雅模式
大循环中判断✅ 提前 continue 跳过减少缩进,提高可读性
不关心循环变量for _ in range(n):_ 约定表示"忽略"

L3 专家层:深入

Python 如何实现流程控制

match/case 语句的编译机制

match 语句并非简单的 if-elif 链翻译,它有专门的字节码优化。

match 语句内部实现:
┌─────────────────────────────────────────────────────────────┐
│          match/case 的编译策略                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  编译时,match 会根据模式复杂度选择策略:                       │
│                                                              │
│  简单字面量匹配(如 case 1, case 2, ...):                   │
│  → 编译为跳转表(类似 switch),O(1) 分发                     │
│                                                              │
│  序列模式匹配(如 case [x, y]):                             │
│  → 编译为 MATCH_SEQUENCE + 长度检查 + 绑定                   │
│                                                              │
│  映射模式匹配(如 case {"key": v}):                         │
│  → 编译为 MATCH_MAPPING + 键检查 + 绑定                      │
│                                                              │
│  类模式匹配(如 case Point(x=0, y=0)):                      │
│  → 编译为 MATCH_CLASS + isinstance + 属性匹配                 │
│                                                              │
│  关键字节码指令(Python 3.10+ 新增):                         │
│  • MATCH_SEQUENCE - 序列匹配                                  │
│  • MATCH_MAPPING  - 映射匹配                                  │
│  • MATCH_CLASS    - 类匹配                                    │
│  • MATCH_KEYS     - 键提取                                    │
│                                                              │
└─────────────────────────────────────────────────────────────┘

验证代码:

python
from dis import dis

# 简单字面量 match(编译为跳转表)
code = """
match x:
    case 1: print("一")
    case 2: print("二")
    case 3: print("三")
    case _: print("未知")
"""
dis(code)
# 可以看到 COPY, LOAD_CONST, COMPARE_OP 等指令序列
# 每个 case 是线性的比较链(简单情况)

# 序列模式 match
code = """
match items:
    case [x]: print(x)
    case [x, y]: print(x, y)
    case [first, *rest]: print(first, rest)
"""
dis(code)
# 可以看到 MATCH_SEQUENCE 指令

# 字典模式 match
code = """
match cmd:
    case {"action": a}: print(a)
    case {"action": a, "target": t}: print(a, t)
"""
dis(code)
# 可以看到 MATCH_MAPPING, MATCH_KEYS 指令
循环的字节码与性能
for vs while 的字节码差异:
┌─────────────────────────────────────────────────────────────┐
│          for/while 的底层执行路径                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  for i in range(n):                                         │
│  ──────────────                                              │
│  1. GET_ITER      获取 range 迭代器                          │
│  2. FOR_ITER      调用 __next__,StopIteration 时跳转        │
│  3. STORE_NAME   绑定到循环变量                              │
│  4. 执行循环体                                                │
│  5. JUMP_ABSOLUTE 回到 FOR_ITER                              │
│                                                             │
│  while i < n:                                                │
│  ──────────                                                  │
│  1. LOAD_NAME    加载 i                                      │
│  2. LOAD_NAME    加载 n                                      │
│  3. COMPARE_OP   执行 < 比较                                  │
│  4. POP_JUMP_IF_FALSE  条件不成立时跳出                      │
│  5. 执行循环体                                                │
│  6. JUMP_ABSOLUTE 回到第1步                                  │
│                                                             │
│  结论:for 使用 C 实现的迭代器,while 每条都用 Python 比较      │
│  → for 通常比 while 快,尤其是大循环                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

验证代码:

python
from dis import dis

dis("for i in range(10): print(i)")
# 关键指令:GET_ITER, FOR_ITER

dis("i = 0\nwhile i < 10: print(i); i += 1")
# 关键指令:COMPARE_OP, POP_JUMP_IF_FALSE
# 每次循环都执行 LOAD_NAME + COMPARE_OP

import timeit

n = 1_000_000

# for 循环
t_for = timeit.timeit(
    "s = 0\nfor i in range(n): s += i",
    setup=f"n = {n}",
    number=10
)

# while 循环
t_while = timeit.timeit(
    "s = i = 0\nwhile i < n: s += i; i += 1",
    setup=f"n = {n}",
    number=10
)

print(f"for:   {t_for:.3f}s")
print(f"while: {t_while:.3f}s")
# for 通常比 while 快 10-20%

性能考量

操作时间复杂度说明
if-else 判断O(1)一次条件计算
if-elif-else (n 分支)O(n) 最坏线性检查直到命中
match (字面量)O(1) ~ O(n)简单情况等同于 if-elif 链
match (序列/映射)O(n)取决于模式复杂度
for item in iterableO(n)遍历所有元素
range(n) 生成O(1)range 是惰性对象,不实际生成所有数字
range(n) 遍历O(n)遍历时才逐个产生值
for vs while (大循环)for 略快for 用 C 级迭代器,无每次 Python 比较开销
守卫子句 vs 深层嵌套相同性能无差异,纯可读性优化
python
import timeit

# range 不占大量内存
import sys
r = range(10_000_000)
print(sys.getsizeof(r))  # 仅 48 字节!

# 等价 list 占用巨大内存
# l = list(range(10_000_000))  # ~80MB,不要执行

# if-elif 链性能
print(timeit.timeit(
    "check(5)",
    setup="""
def check(x):
    if x == 0: return "a"
    elif x == 1: return "b"
    elif x == 2: return "c"
    elif x == 3: return "d"
    elif x == 4: return "e"
    elif x == 5: return "f"
    elif x == 6: return "g"
    elif x == 7: return "h"
    elif x == 8: return "i"
    elif x == 9: return "j"
    else: return "z"
""",
    number=10_000_000
))
# → 匹配最后一个分支(x=5)需要 6 次比较

知识关联

流程控制知识关联:

                    ┌─────────────────┐
                    │   条件表达式     │
                    │   真值判断      │
                    │  (运算符章节)   │
                    └─────────────────┘

            ┌─────────────┼─────────────┐
            ↓             ↓             ↓
      ┌───────────┐ ┌───────────┐ ┌───────────┐
      │ if-else   │ │  match    │ │ 三元运算符│
      │ 基础分支  │ │ 模式匹配  │ │ 紧凑表达式│
      └───────────┘ └───────────┘ └───────────┘
            │             │             │
            ↓             ↓             ↓
      ┌───────────────────────────────────────┐
      │        守卫子句(guard clause)        │
      │        减少嵌套,提前返回              │
      └───────────────────────────────────────┘

                    ┌─────────────────┐
                    │   可迭代对象     │
                    │   __iter__      │
                    │   __next__      │
                    └─────────────────┘

            ┌─────────────┼─────────────┐
            ↓             ↓             ↓
      ┌───────────┐ ┌───────────┐ ┌───────────┐
      │ for 循环  │ │ while 循环│ │ range()   │
      │ 遍历迭代  │ │ 条件循环  │ │ 惰性序列  │
      └───────────┘ └───────────┘ └───────────┘
            │             │
            ↓             ↓
      ┌───────────────────────────────────────┐
      │  循环控制:break / continue / else    │
      │  异常控制:try-except-else-finally    │
      └───────────────────────────────────────┘

设计动机

设计选择原因影响
Python 没有传统的 switch/case(3.10 之前)早期设计哲学:if-elif 够用3.10 的 match 比传统 switch 更强大
match/case 不穿透(无 fall-through)避免 C 语言 switch 的常见 bug不需要 break,每个 case 独立
for-else 语法else 表示"正常结束(未被 break)"命名不直观,但提供了搜索模式的优雅写法
range 惰性生成避免大列表内存占用range(10**9) 只占 ~48 字节
break/continue 只影响最内层循环简单明确没有 goto/label,多层级跳出需标志变量或异常

本章小结

┌─────────────────────────────────────────────────────────────┐
│                      流程控制 知识要点                        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   条件语句:                                                 │
│   ✓ if / if-else / if-elif-else                            │
│   ✓ 三元运算符:值 1 if 条件 else 值 2                       │
│   ✓ match 语句(Python 3.10+):模式匹配                    │
│   ✓ pass 语句:占位符,保持语法完整                         │
│                                                             │
│   循环语句:                                                 │
│   ✓ for 循环:遍历序列                                      │
│   ✓ while 循环:条件循环                                    │
│   ✓ range():生成数字序列                                   │
│                                                             │
│   循环控制:                                                 │
│   ✓ break:跳出整个循环                                     │
│   ✓ continue:跳过本次循环                                  │
│                                                             │
│   实际应用:                                                 │
│   ✓ 用户交互、游戏循环、菜单系统                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘