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 的对比
| 特性 | match | if-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 | 跳过本次循环 | 继续下一次循环 |
小结
本章我们学习了:
- 条件语句(if、elif、else)
- match 语句(结构化模式匹配)
- 简单值匹配
- 序列模式匹配
- 字典模式匹配
- 类实例匹配
- 守卫子句
- for 循环的使用
- while 循环的使用
- 循环控制语句(break、continue、pass)
- 循环的 else 子句
- 多个实战练习
练习
- 打印 1 到 100 中能被 3 整除的数
- 求斐波那契数列的前 20 项
- 找出 100 以内的所有素数
- 模拟用户登录(最多尝试 3 次)