7 minutes
条件判断与分支控制
到目前为止,我们学习的程序都是按顺序从上到下逐行执行的。但在实际编程中,我们需要程序能够根据不同的条件做出不同的决策——这就要用到条件判断。条件判断是程序控制流的三大结构之一(顺序、分支、循环)。
if/elif/else 基本结构
Python 使用 if、elif、else 关键字来实现分支控制,最特别的是用缩进而不是花括号来划定代码块。
基本语法
# if 语句的基本结构
age = 18
if age >= 18:
print("你已成年")
print("可以考驾照了")
print("程序结束")
# 输出:
# 你已成年
# 可以考驾照了
# 程序结束
if/else 二选一
# if/else 结构
age = 16
if age >= 18:
print("允许进入")
else:
print("禁止进入")
# 输出:禁止进入
if/elif/else 多选一
# 多条件分支
score = 85
if score >= 90:
grade = "优秀"
elif score >= 80:
grade = "良好"
elif score >= 70:
grade = "中等"
elif score >= 60:
grade = "及格"
else:
grade = "不及格"
print(f"成绩等级: {grade}") # 成绩等级: 良好
# 注意:只会执行第一个满足条件的分支
score = 95
if score >= 90:
print("优秀") # 只执行这个
elif score >= 80:
print("良好") # 不会执行
elif score >= 60:
print("及格") # 不会执行
Python 条件判断的特点
# 1. 不需要括号(但可以加)
x = 5
if x > 0: # ✅ Python 风格
print("正数")
if (x > 0): # ✅ 也可以,但多余
print("正数")
# 2. 使用缩进定义代码块
if True:
print("缩进必须是4个空格")
print("同一代码块缩进必须一致")
# 3. 条件后面要有冒号
# if x > 0 # SyntaxError! 忘记冒号
真值(Truthiness)与假值(Falsy)
在 Python 中,任何值都可以用于条件判断,它有一个"真值"概念:
# 假值(Falsy):在条件判断中相当于 False
falsy_values = [
False, # 布尔假
None, # 空值
0, # 零
0.0, # 零浮点数
"", # 空字符串
[], # 空列表
(), # 空元组
{}, # 空字典
set(), # 空集合
]
for val in falsy_values:
if not val:
print(f"假值: {repr(val)}")
# 其他所有值都是真值(Truthy)
truthy_values = [
True,
1,
-1,
"hello",
"False", # 非空字符串,是 True!
[0],
(None,),
{"": 1},
]
for val in truthy_values:
if val:
print(f"真值: {repr(val)}")
真值判断的实用技巧
# 用真值判断简化代码
# 不好的写法
name = input("请输入姓名: ")
if name != "":
print(f"你好, {name}")
# 更好的写法(利用空字符串是假值)
name = input("请输入姓名: ")
if name:
print(f"你好, {name}")
# 检查列表是否为空
items = []
if len(items) > 0: # 不够 Pythonic
print("有内容")
if items: # Pythonic 写法
print("有内容")
# 检查变量是否非 None
result = get_result()
if result is not None:
print(f"结果: {result}")
# 注意不要混淆 None 和空值
value = 0
if value: # False(0 是假值)
print("不会执行")
if value is not None: # True(0 不是 None)
print("会执行")
短路过早求值
逻辑运算符 and 和 or 使用短路求值策略:
# and 短路:遇到 False 就停止
def check_left():
print("检查左边")
return False
def check_right():
print("检查右边")
return True
result = check_left() and check_right()
# 只输出"检查左边",因为第一个条件已经是 False
# check_right 没有被调用
# or 短路:遇到 True 就停止
result = check_right() or check_left()
# 只输出"检查右边",因为第一个条件已经是 True
# check_left 没有被调用
# 实际应用:安全访问和默认值
user = {"name": "张三"}
age = user.get("age") or 18 # 如果 age 是假值(None/0),使用默认值
print(age) # 18
name = user.get("name") or "匿名"
print(name) # 张三(非空字符串是真值,所以不取默认值)
# 更精确的 None 检查场景(0 是有效值)
score = 0
final_score = score or 100 # 错误!0 是假值,会返回 100
print(final_score) # 100(不是我们想要的)
final_score = score if score is not None else 100 # 正确
print(final_score) # 0(正确)
三元表达式(条件表达式)
Python 支持行内的条件表达式,语法为 value_if_true if condition else value_if_false:
# 基本语法
age = 20
status = "成年" if age >= 18 else "未成年"
print(status) # 成年
# 对比传统的 if/else
if age >= 18:
status = "成年"
else:
status = "未成年"
# 嵌套三元表达式(不推荐过于复杂)
score = 85
level = "优秀" if score >= 90 else ("良好" if score >= 80 else "及格")
print(level) # 良好
# 上面的嵌套三元等价于:
if score >= 90:
level = "优秀"
elif score >= 80:
level = "良好"
else:
level = "及格"
# 三元表达式在列表推导式中很实用
numbers = [1, 2, 3, 4, 5]
labels = ["偶数" if n % 2 == 0 else "奇数" for n in numbers]
print(labels) # ['奇数', '偶数', '奇数', '偶数', '奇数']
# 三元表达式在 f-string 中也很方便
price = 120
print(f"价格: {price} 元{'(含运费)' if price < 100 else '(免运费)'}")
# 价格: 120 元(免运费)
match/case 语句(Python 3.10+)
Python 3.10 引入了 match/case 语句,类似于其他语言的 switch/case:
基本匹配
# match/case 基本用法
def get_day_type(day):
match day:
case 1 | 2 | 3 | 4 | 5: # 多个值用 | 连接
return "工作日"
case 6 | 7:
return "周末"
case _: # _ 匹配任何值(默认分支)
return "无效"
print(get_day_type(1)) # 工作日
print(get_day_type(6)) # 周末
print(get_day_type(0)) # 无效
字面量匹配
# 匹配字面量
def respond(command):
match command.lower():
case "hello" | "hi" | "hey":
return "你好!"
case "bye" | "goodbye":
return "再见!"
case "help":
return "输入命令来交互"
case _:
return f"未知命令: {command}"
print(respond("Hello")) # 你好!
print(respond("bye")) # 再见!
print(respond("test")) # 未知命令: test
模式匹配
# 解构匹配——match/case 的强大之处
def process_point(point):
match point:
case (0, 0):
return "原点"
case (0, y):
return f"在 Y 轴上, y={y}"
case (x, 0):
return f"在 X 轴上, x={x}"
case (x, y):
return f"在 ({x}, {y}) 位置"
case _:
return "不是二维点"
print(process_point((0, 0))) # 原点
print(process_point((0, 5))) # 在 Y 轴上, y=5
print(process_point((3, 0))) # 在 X 轴上, x=3
print(process_point((3, 4))) # 在 (3, 4) 位置
更复杂的模式匹配
# 匹配字典
def analyze_user(user):
match user:
case {"name": name, "age": age}:
return f"{name}, {age}岁"
case {"name": name}:
return f"{name}, 年龄未知"
case _:
return "无效用户"
print(analyze_user({"name": "张三", "age": 20})) # 张三, 20岁
print(analyze_user({"name": "李四"})) # 李四, 年龄未知
# 匹配带有条件的模式
def classify_number(n):
match n:
case 0:
return "零"
case n if n < 0: # 守卫条件
return "负数"
case n if n < 10:
return "一位数"
case n if n < 100:
return "两位数"
case _:
return "很大的数"
print(classify_number(-5)) # 负数
print(classify_number(7)) # 一位数
print(classify_number(42)) # 两位数
print(classify_number(999)) # 很大的数
嵌套条件判断
# 嵌套条件判断(条件中有条件)
def check_access(age, has_id, is_vip):
if age >= 18:
if has_id:
if is_vip:
return "VIP 通道欢迎您"
else:
return "普通通道请进"
else:
return "请出示身份证"
else:
return "未成年人禁止进入"
print(check_access(20, True, True)) # VIP 通道欢迎您
print(check_access(20, True, False)) # 普通通道请进
print(check_access(20, False, False)) # 请出示身份证
print(check_access(16, True, False)) # 未成年人禁止进入
使用布尔逻辑简化嵌套
# 有时可以用 and/or 简化嵌套
def check_access_v2(age, has_id, is_vip):
if age < 18:
return "未成年人禁止进入"
if not has_id:
return "请出示身份证"
return "VIP 通道欢迎您" if is_vip else "普通通道请进"
# 使用提前返回减少嵌套深度
def validate_form(data):
"""表单验证——使用提前返回"""
if not data.get("name"):
return "请输入姓名"
if not data.get("email"):
return "请输入邮箱"
if "@" not in data["email"]:
return "邮箱格式不正确"
if len(data.get("password", "")) < 6:
return "密码至少6位"
return "验证通过"
print(validate_form({"name": "张三", "email": "test"})) # 邮箱格式不正确
常见模式
模式1:范围检查
# 使用链式比较让范围检查更清晰
temperature = 25
# 不像 Python 的写法
if temperature >= 0 and temperature <= 30:
print("温度适宜")
# Pythonic 的写法
if 0 <= temperature <= 30:
print("温度适宜")
# 多个范围
if temperature < 0:
print("结冰了")
elif 0 <= temperature <= 15:
print("有点冷")
elif 15 < temperature <= 25:
print("舒适")
elif 25 < temperature <= 35:
print("有点热")
else:
print("太热了")
模式2:多值检查
# 不好的写法
if color == "red" or color == "green" or color == "blue":
print("基础色")
# 好的写法
if color in ("red", "green", "blue"):
print("基础色")
# 用集合检查更高效(大量值时)
primary_colors = {"red", "green", "blue"}
if color in primary_colors:
print("基础色")
模式3:None 检查
# 安全的属性访问
def get_user_city(user):
if user is not None:
address = user.get("address")
if address is not None:
return address.get("city")
return "未知"
# 简化版(利用 and 短路)
def get_user_city_v2(user):
if user and user.get("address"):
return user["address"].get("city", "未知")
return "未知"
# 测试
user1 = {"name": "张三", "address": {"city": "北京", "street": "长安街"}}
user2 = {"name": "李四"}
user3 = None
print(get_user_city_v2(user1)) # 北京
print(get_user_city_v2(user2)) # 未知
print(get_user_city_v2(user3)) # 未知
模式4:字典映射替代多重分支
# 当分支很多时,字典映射往往比 if/elif 更优雅
# 不好的写法
def get_weekday_name(day):
if day == 1:
return "周一"
elif day == 2:
return "周二"
elif day == 3:
return "周三"
# ... 一共 7 个分支
# 好的写法:字典映射
weekdays = {
1: "周一", 2: "周二", 3: "周三",
4: "周四", 5: "周五", 6: "周六", 7: "周日",
}
def get_weekday_name(day):
return weekdays.get(day, "无效的日期")
print(get_weekday_name(3)) # 周三
print(get_weekday_name(8)) # 无效的日期
模式5:使用函数字典
# 字典映射到函数(更灵活的分支替代方案)
def add(a, b): return a + b
def subtract(a, b): return a - b
def multiply(a, b): return a * b
def divide(a, b): return a / b if b != 0 else "不能除零"
operations = {
"+": add,
"-": subtract,
"*": multiply,
"/": divide,
}
def calculate(a, op, b):
func = operations.get(op)
if func:
return func(a, b)
return "不支持的运算符"
print(calculate(10, "+", 5)) # 15
print(calculate(10, "*", 5)) # 50
print(calculate(10, "^", 5)) # 不支持的运算符
实践练习:猜数字游戏
# guess_number.py
import random
print("=" * 40)
print(" 猜数字游戏")
print("=" * 40)
print("我在想一个 1~100 之间的数字...")
target = random.randint(1, 100)
attempts = 0
max_attempts = 7
while attempts < max_attempts:
guess = input(f"第 {attempts + 1}/{max_attempts} 次猜测: ")
# 验证输入
if not guess.isdigit():
print("请输入有效的数字!")
continue
guess = int(guess)
attempts += 1
# 判断大小
if guess < target:
print("猜小了,再大一点!")
elif guess > target:
print("猜大了,再小一点!")
else:
print(f"恭喜你猜对了!就是 {target}")
print(f"你用了 {attempts} 次猜中了")
break
else:
# while 循环正常结束(没有 break)时执行
print(f"\n机会用完了!正确答案是 {target}")
# 判断是否继续
again = input("\n再来一局?(y/n): ").lower()
if again in ("y", "yes"):
print("开始新游戏...")
elif again in ("n", "no"):
print("再见!")
else:
print("无法识别的输入,程序退出")
常见陷阱
1. 使用 = 而不是 ==
# 错误
# if x = 5: # SyntaxError! = 是赋值,不是比较
# print(x)
# 正确
if x == 5:
print(x)
2. 真值检查的误解
# 注意区别
value = "False"
if value: # True!非空字符串是真值
print("执行")
3. 悬空的 else
# Python 使用缩进确定 else 属于哪个 if
x = 0
y = 1
if x > 0:
if y > 0:
print("x 和 y 都是正数")
else:
print("x 不是正数") # 这个 else 属于第一个 if!
4. 不必要的条件判断
# 不好的写法
if flag == True:
print("yes")
# 好的写法
if flag:
print("yes")
# 不好的写法
if len(items) > 0:
print("有元素")
# 好的写法
if items:
print("有元素")
小结
在这篇文章中,我们学习了:
- if/elif/else 三种基本分支结构
- 真值(Truthiness) 的概念和假值列表
- 短路求值的原理和实际应用
- 三元表达式的简洁用法
- match/case 模式匹配(Python 3.10+)
- 嵌套条件判断和提前返回模式
- 常见的条件判断设计模式
- 用字典映射替代长串的 if/elif
下一步
条件判断让程序有了决策能力。在最后一篇基础入门文章中,我们将学习循环结构,让程序能够重复执行代码块,处理批量数据。
实践建议:写一个简单的登录验证程序,检查用户名和密码,支持最多 3 次尝试。如果连续输错,锁定账号一段时间。
Summary: 条件判断与分支控制全解析。