到目前为止,我们学习的程序都是按顺序从上到下逐行执行的。但在实际编程中,我们需要程序能够根据不同的条件做出不同的决策——这就要用到条件判断。条件判断是程序控制流的三大结构之一(顺序、分支、循环)。

if/elif/else 基本结构

Python 使用 ifelifelse 关键字来实现分支控制,最特别的是用缩进而不是花括号来划定代码块。

基本语法

# 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("会执行")

短路过早求值

逻辑运算符 andor 使用短路求值策略:

# 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("有元素")

小结

在这篇文章中,我们学习了:

  1. if/elif/else 三种基本分支结构
  2. 真值(Truthiness) 的概念和假值列表
  3. 短路求值的原理和实际应用
  4. 三元表达式的简洁用法
  5. match/case 模式匹配(Python 3.10+)
  6. 嵌套条件判断和提前返回模式
  7. 常见的条件判断设计模式
  8. 字典映射替代长串的 if/elif

下一步

条件判断让程序有了决策能力。在最后一篇基础入门文章中,我们将学习循环结构,让程序能够重复执行代码块,处理批量数据。

实践建议:写一个简单的登录验证程序,检查用户名和密码,支持最多 3 次尝试。如果连续输错,锁定账号一段时间。

Summary: 条件判断与分支控制全解析。