跳到主要内容

Python 控制流

控制流用于控制程序的执行顺序。本章将介绍条件语句和循环结构。

条件语句

if 语句

基本的 if 语句结构:

age = 18

if age >= 18:
print("你已经成年了")

if-else 语句

age = 16

if age >= 18:
print("你已经成年了")
else:
print("你还未成年")

if-elif-else 语句

score = 85

if score >= 90:
print("优秀")
elif score >= 80:
print("良好")
elif score >= 60:
print("及格")
else:
print("不及格")

嵌套条件

age = 25
is_student = True

if age >= 18:
if is_student:
print("成年学生")
else:
print("成年非学生")
else:
print("未成年")

简化写法

# 单行 if 语句
age = 20
status = "成年" if age >= 18 else "未成年"
print(status) # 输出:成年

match 语句(结构化模式匹配)

Python 3.10 引入了 match 语句,提供了一种强大的结构化模式匹配机制。它类似于其他语言中的 switch 语句,但功能更加强大。

基本语法

match 表达式:
case 模式1:
# 匹配模式1时执行
case 模式2:
# 匹配模式2时执行
case _:
# 默认情况(相当于其他语言的 default)

简单值匹配

def http_status(status):
match status:
case 200:
return "OK"
case 404:
return "Not Found"
case 500:
return "Server Error"
case _:
return "Unknown Status"

print(http_status(200)) # OK
print(http_status(404)) # Not Found
print(http_status(999)) # Unknown Status

或模式(|)

使用 | 可以匹配多个值:

def classify_grade(score):
match score:
case 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100:
return "优秀"
case 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89:
return "良好"
case 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79:
return "及格"
case _:
return "不及格"

# 更简洁的写法使用范围
print(classify_grade(85)) # 良好

捕获模式

可以将匹配的值捕获到变量中:

point = (3, 0)

match point:
case (0, 0):
print("原点")
case (x, 0): # 捕获 x 坐标,y 必须是 0 才匹配
print(f"x轴上,x={x}")
case (0, y): # 捕获 y 坐标,x 必须是 0 才匹配
print(f"y轴上,y={y}")
case (x, y): # 捕获两个坐标
print(f"点 ({x}, {y})")

解释:当 point = (3, 0) 时,虽然 (0, y)(x, y) 都能匹配,但 (x, 0) 先被检查,所以它会匹配成功,输出 "x轴上,x=3"。注意这里 (x, 0) 中的 0 是字面量匹配,而 x 是捕获变量。

序列模式匹配

可以匹配列表、元组等序列:

def describe_list(items):
match items:
case []:
return "空列表"
case [single]: # 只有一个元素
return f"单元素列表: {single}"
case [first, *rest]: # 解构列表
return f"首元素: {first}, 其余: {rest}"

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

匹配列表的具体结构

def analyze_command(command):
match command.split():
case ["quit"]:
return "退出程序"
case ["load", filename]:
return f"加载文件: {filename}"
case ["save", filename]:
return f"保存文件: {filename}"
case ["copy", source, dest]:
return f"复制 {source}{dest}"
case ["help"]:
return "显示帮助信息"
case _:
return f"未知命令: {command}"

print(analyze_command("load data.txt")) # 加载文件: data.txt
print(analyze_command("copy a.txt b.txt")) # 复制 a.txt 到 b.txt
print(analyze_command("unknown")) # 未知命令: unknown

字典模式匹配

可以匹配字典的结构:

def process_user(data):
match data:
case {"name": str(name), "age": int(age)}:
return f"用户: {name}, 年龄: {age}"
case {"name": str(name)}:
return f"用户: {name}, 年龄未知"
case {"error": str(message)}:
return f"错误: {message}"
case _:
return "无效数据"

print(process_user({"name": "张三", "age": 25}))
# 用户: 张三, 年龄: 25

print(process_user({"name": "李四"}))
# 用户: 李四, 年龄未知

print(process_user({"error": "连接失败"}))
# 错误: 连接失败

匹配类的实例(数据类)

from dataclasses import dataclass

@dataclass
class Point:
x: float
y: float

@dataclass
class Circle:
center: Point
radius: float

@dataclass
class Rectangle:
top_left: Point
bottom_right: Point

def describe_shape(shape):
match shape:
case Point(0, 0):
return "原点"
case Point(x, y):
return f"点 ({x}, {y})"
case Circle(Point(0, 0), radius):
return f"以原点为圆心,半径为 {radius} 的圆"
case Circle(center, radius):
return f"圆心 {center},半径 {radius}"
case Rectangle(Point(x1, y1), Point(x2, y2)):
width = abs(x2 - x1)
height = abs(y2 - y1)
return f"矩形,宽 {width},高 {height}"
case _:
return "未知形状"

print(describe_shape(Point(3, 4)))
# 点 (3, 4)

print(describe_shape(Circle(Point(0, 0), 5)))
# 以原点为圆心,半径为 5 的圆

print(describe_shape(Rectangle(Point(0, 0), Point(10, 20))))
# 矩形,宽 10,高 20

带守卫子句的 case

守卫子句允许在 case 后添加 if 条件,用于表达更精确的匹配逻辑。当模式匹配成功后,还需要进一步判断条件时使用。

def categorize_age(person):
match person:
case {"age": int(age)} if age < 0:
return "年龄不能为负数"
case {"age": int(age)} if age < 13:
return "儿童"
case {"age": int(age)} if age < 20:
return "青少年"
case {"age": int(age)} if age < 65:
return "成年人"
case {"age": int(age)}:
return "老年人"
case _:
return "年龄信息缺失"

print(categorize_age({"age": 8})) # 儿童
print(categorize_age({"age": 25})) # 成年人
print(categorize_age({"age": 70})) # 老年人
print(categorize_age({})) # 年龄信息缺失

工作原理:匹配过程是顺序进行的。首先检查 case {"age": int(age)} if age < 0,如果字典中有 age 键且值可以转换为 int,则 age 变量被赋值。然后判断 if age < 0 条件,满足则执行对应分支。

守卫子句的实际应用:

def validate_input(data):
"""验证用户输入的边界条件"""
match data:
case {"password": str(pw)} if len(pw) < 8:
return "密码长度不能少于8位"
case {"password": str(pw)} if not any(c.isdigit() for c in pw):
return "密码必须包含数字"
case {"password": str(pw)} if not any(c.isupper() for c in pw):
return "密码必须包含大写字母"
case {"password": str(pw), "confirm": str(confirm)} if pw != confirm:
return "两次密码不一致"
case {"password": str(pw), "confirm": str(confirm)} if pw == confirm:
return "注册成功"
case _:
return "请提供完整的注册信息"

match 与 if-elif 的对比

特性matchif-elif
结构化数据匹配优秀一般
代码可读性中等
解构能力
适用场景数据结构匹配条件判断

选择建议

  • 当需要根据数据结构进行多分支处理时,使用 match
  • 当进行简单的条件判断时,使用 if-elif

循环

for 循环

基本语法

# 遍历列表
fruits = ["苹果", "香蕉", "橙子"]
for fruit in fruits:
print(fruit)

使用 range()

range() 函数生成一个数字序列:

# range(stop) - 从 0 到 stop-1
for i in range(5):
print(i) # 0, 1, 2, 3, 4

# range(start, stop) - 从 start 到 stop-1
for i in range(2, 6):
print(i) # 2, 3, 4, 5

# range(start, stop, step) - 指定步长
for i in range(0, 10, 2):
print(i) # 0, 2, 4, 6, 8

# 倒序
for i in range(5, 0, -1):
print(i) # 5, 4, 3, 2, 1

遍历字符串

text = "Python"
for char in text:
print(char)

遍历字典

person = {"name": "张三", "age": 20, "city": "北京"}

# 遍历键
for key in person:
print(key)

# 遍历值
for value in person.values():
print(value)

# 遍历键值对
for key, value in person.items():
print(f"{key}: {value}")

while 循环

基本语法:

count = 0
while count < 5:
print(count)
count += 1

死循环(谨慎使用)

while True:
user_input = input("输入 'quit' 退出:")
if user_input == "quit":
break
print(f"你输入了:{user_input}")

循环控制

break - 跳出循环

for i in range(10):
if i == 5:
break
print(i) # 输出 0, 1, 2, 3, 4

continue - 跳过当前迭代

for i in range(5):
if i == 2:
continue
print(i) # 输出 0, 1, 3, 4(跳过 2)

pass - 占位符

for i in range(5):
if i == 2:
pass # 什么都不做,继续执行
print(i)

循环else子句

循环可以有一个 else 子句,当循环正常结束(不是因为 break)时执行:

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

# 如果使用 break,则 else 不会执行
for i in range(3):
if i == 1:
break
print(i)
else:
print("循环正常结束") # 不会执行

实战练习

练习 1:计算 1 到 100 的和

total = 0
for i in range(1, 101):
total += i
print(f"1+2+...+100 = {total}")

练习 2:打印九九乘法表

for i in range(1, 10):
for j in range(1, i + 1):
print(f"{j}*{i}={i*j}", end="\t")
print()

练习 3:判断素数

num = 17
is_prime = True

if num < 2:
is_prime = False
else:
for i in range(2, int(num**0.5) + 1):
if num % i == 0:
is_prime = False
break

print(f"{num}是素数:{is_prime}")

练习 4:猜数字游戏

import random

target = random.randint(1, 100)
guess = 0
attempts = 0

while guess != target:
guess = int(input("请输入一个1-100的数字:"))
attempts += 1

if guess > target:
print("猜大了!")
elif guess < target:
print("猜小了!")

print(f"恭喜你猜对了!共用了{attempts}次")

练习 5:输出菱形

n = 5

# 上半部分
for i in range(1, n + 1):
print(" " * (n - i) + "*" * (2 * i - 1))

# 下半部分
for i in range(n - 1, 0, -1):
print(" " * (n - i) + "*" * (2 * i - 1))

pass、break 和 continue 的区别

关键字作用说明
pass空操作不做任何事,常用作占位符
break跳出循环终止当前循环
continue跳过本次循环继续下一次循环

小结

本章我们学习了:

  1. 条件语句(if、elif、else)
  2. match 语句(结构化模式匹配)
    • 简单值匹配
    • 序列模式匹配
    • 字典模式匹配
    • 类实例匹配
    • 守卫子句
  3. for 循环的使用
  4. while 循环的使用
  5. 循环控制语句(break、continue、pass)
  6. 循环的 else 子句
  7. 多个实战练习

练习

  1. 打印 1 到 100 中能被 3 整除的数
  2. 求斐波那契数列的前 20 项
  3. 找出 100 以内的所有素数
  4. 模拟用户登录(最多尝试 3 次)