python

关注公众号 jb51net

关闭
首页 > 脚本专栏 > python > Python if-elif-else多条件分支

Python基础指南之if-elif-else多条件分支全面解析

作者:星河耀银海

本文全面解析Python中if-elif-else多条件分支的使用技巧, 文章通过大量代码示例演示了如何编写既高效又易维护的多分支逻辑,并强调了条件顺序对程序正确,希望对大家有所帮助

一、开篇:从"如果下雪就不去"到复杂的决策树

生活中充满了多条件决策:如果不下雨就去公园,如果下雨但有伞也去,如果下雨又没伞就不去。编程中的业务逻辑往往比这更复杂——优惠券是否可用、用户是否有权限、订单能否取消——每一个决策都涉及多个条件和多个分支。

上一篇文章我们学习了if语句的三种基本结构,今天我们要深入if-elif-else多条件分支的每一个细节,从条件编排到性能优化,从代码风格到重构技巧,让你写出既正确又优雅的多分支代码。

# 这看起来很简单
if condition1:
    action1()
elif condition2:
    action2()
elif condition3:
    action3()
else:
    default_action()

# 但真实世界的问题是这样的:
# - 10个elif中哪个应该排第一?
# - 条件和条件之间有重叠怎么办?
# - 如何避免写出一座"if山"?
# - 什么时候该用字典映射替代if-elif?

带着这些问题,我们开始今天的学习。

二、if-elif-else的执行机制深入

2.1 互斥性:命中即停止

if-elif-else最核心的特性是互斥——一旦某个条件为True,后面的条件都会被跳过:

def demonstrate_exclusivity(value):
    """演示elif的互斥性"""
    print(f"\n输入: {value}")
    
    if value > 0:
        print("  → 第一个分支: 正数")
        value += 100  # 修改了value
    elif value > 0:   # 这个条件永远不检查(因为上面已经匹配)
        print("  → 这个永远不会打印")
    elif value > -10:
        print("  → 负数但大于-10")
    else:
        print("  → 其他情况")
    
    print(f"  最终值: {value}")

demonstrate_exclusivity(5)     # 只进入第一个分支
demonstrate_exclusivity(-3)    # 跳过第一个(-3>0为False),进入第三个
demonstrate_exclusivity(-20)   # 最终进入else

# ⚠️ 注意:一旦匹配,即使变量在分支中被修改,后续elif也不会重新检查

2.2 每个elif独立计算条件

# 每个elif的条件表达式都被独立计算
# 而且只在前面所有条件都为False时才计算

def expensive_check(threshold):
    """模拟一个耗时的检查"""
    print(f"    [执行检查: 阈值={threshold}]")
    return True

# 检查顺序很重要!
def check_value(x):
    print(f"检查 x={x}:")
    if x < 0:                          # 总是先检查
        print("  → 负数")
    elif x > 100 and expensive_check(100):  # 只在x>=0时检查
        print("  → 大数(通过检查)")
    elif x > 50 and expensive_check(50):    # 只在x<=100时检查
        print("  → 中等数(通过检查)")
    else:
        print("  → 其他")

check_value(-5)    # expensive_check不会被调用
check_value(150)   # 只调用expensive_check(100)
check_value(80)    # 只调用expensive_check(50)

2.3 else是可选的

# 有else:兜底分支
def get_weekday_name(day_num):
    if day_num == 1:
        return "星期一"
    elif day_num == 2:
        return "星期二"
    # ... 
    elif day_num == 7:
        return "星期日"
    else:
        return f"无效的数字: {day_num}(应该1-7)"

# 没有else:不匹配就返回None(隐式)
def get_season(month):
    if 3 <= month <= 5:
        return "春季"
    elif 6 <= month <= 8:
        return "夏季"
    elif 9 <= month <= 11:
        return "秋季"
    elif month == 12 or 1 <= month <= 2:
        return "冬季"
    # 如果都不匹配,返回None

三、条件编排的艺术

3.1 从最严格到最宽松

# 原则:条件范围从小到大排列
# 就像一个漏斗——先过细网,再过粗网

# ✅ 正确:从严格到宽松
def classify_score(score):
    if score == 100:
        return "🏆 满分!"
    elif score >= 90:
        return "🌟 优秀"
    elif score >= 80:
        return "👍 良好"
    elif score >= 70:
        return "📚 中等"
    elif score >= 60:
        return "✏️ 及格"
    else:
        return "📖 不及格"

# ❌ 错误:从宽松到严格
def classify_score_bad(score):
    if score >= 0:         # 这个条件覆盖了几乎所有情况!
        return "有分数"
    elif score >= 90:      # 永远不会到达这里
        return "优秀"

# 特殊情况:如果某个非常具体的条件应该优先触发
def process_payment(amount, is_vip, is_first_purchase):
    # 特例优先
    if amount == 0:
        return "免费订单,无需支付"
    # 具体条件在前
    elif is_vip and is_first_purchase:
        return "VIP首单,享受折上折"
    elif is_vip:
        return "VIP用户,享受会员折扣"
    elif is_first_purchase:
        return "首单用户,享受新用户优惠"
    # 通用条件在后
    elif amount >= 500:
        return "满500减50"
    else:
        return "正常支付"

3.2 从最常见到最罕见

从性能角度考虑,把最常命中的条件放前面可以减少条件检查次数:

def get_user_level_label(level):
    """用户等级标签 —— 按出现频率排序"""
    # 假设:普通用户占70%,VIP占20%,其他占10%
    if level == "normal":
        return "普通用户"       # 70% 命中这里,一次检查
    elif level == "vip":
        return "VIP会员"       # 90% 命中前两个
    elif level == "svip":
        return "超级会员"      # 95% 命中前三个
    elif level == "admin":
        return "管理员"        # 99% 命中前四个
    else:
        return "未知等级"      # 兜底

# 这个排序可以减少平均条件检查次数
# 如果把admin放第一个,99%的情况都要检查两次才能找到

3.3 先快后慢

把计算开销小的条件放前面:

import re

def classify_text(text):
    """文本分类 —— 先做便宜的检查"""
    
    # 快速检查:空字符串
    if not text:
        return "空文本"
    
    # 快速检查:长度
    if len(text) < 10:
        return "短文本"
    
    # 快速检查:纯数字
    if text.isdigit():
        return "纯数字"
    
    # 快速检查:简单字符特征
    if text.startswith("http"):
        return "可能是一个URL"
    
    # 较慢的检查:正则匹配(放后面)
    if re.match(r'^[\w\.-]+@[\w\.-]+\.\w+$', text):
        return "邮箱地址"
    
    if re.match(r'^1[3-9]\d{9}$', text):
        return "手机号码"
    
    # 最慢的检查
    if len(text) > 1000 and "重要" in text and "紧急" in text:
        return "重要紧急的长文本"
    
    return "普通文本"

四、避免"if山"的重构技巧

4.1 字典映射法

当每个分支只是简单的值返回时:

# ❌ if山
def get_error_message(code):
    if code == 200:
        return "OK"
    elif code == 201:
        return "Created"
    elif code == 204:
        return "No Content"
    elif code == 400:
        return "Bad Request"
    elif code == 401:
        return "Unauthorized"
    elif code == 403:
        return "Forbidden"
    elif code == 404:
        return "Not Found"
    elif code == 500:
        return "Internal Server Error"
    elif code == 502:
        return "Bad Gateway"
    elif code == 503:
        return "Service Unavailable"
    else:
        return "Unknown"

# ✅ 字典映射
HTTP_MESSAGES = {
    200: "OK",
    201: "Created",
    204: "No Content",
    400: "Bad Request",
    401: "Unauthorized",
    403: "Forbidden",
    404: "Not Found",
    500: "Internal Server Error",
    502: "Bad Gateway",
    503: "Service Unavailable",
}

def get_error_message_v2(code):
    return HTTP_MESSAGES.get(code, "Unknown")

4.2 字典映射 + 函数

当分支需要执行不同逻辑时:

# ❌ 长if-elif链
def handle_command(command, *args):
    if command == "create":
        # 20行创建逻辑
        return create_user(*args)
    elif command == "delete":
        # 15行删除逻辑
        return delete_user(*args)
    elif command == "update":
        # 20行更新逻辑
        return update_user(*args)
    elif command == "list":
        # 10行列显逻辑
        return list_users(*args)
    elif command == "export":
        # 15行导出逻辑
        return export_users(*args)
    else:
        return f"未知命令: {command}"

# ✅ 命令模式(字典映射到函数)
COMMAND_HANDLERS = {
    "create": create_user,
    "delete": delete_user,
    "update": update_user,
    "list": list_users,
    "export": export_users,
}

def handle_command_v2(command, *args):
    handler = COMMAND_HANDLERS.get(command)
    if handler is None:
        return f"未知命令: {command}"
    return handler(*args)

4.3 策略模式(条件类)

当每个分支逻辑非常复杂时:

from abc import ABC, abstractmethod

# 策略接口
class DiscountStrategy(ABC):
    @abstractmethod
    def calculate(self, amount):
        pass

# 具体策略
class NoDiscount(DiscountStrategy):
    def calculate(self, amount):
        return amount

class PercentageDiscount(DiscountStrategy):
    def __init__(self, percent):
        self.percent = percent
    
    def calculate(self, amount):
        return amount * (1 - self.percent / 100)

class FixedDiscount(DiscountStrategy):
    def __init__(self, fixed_amount):
        self.fixed_amount = fixed_amount
    
    def calculate(self, amount):
        return max(0, amount - self.fixed_amount)

class BuyOneGetOneFree(DiscountStrategy):
    def calculate(self, amount):
        return amount / 2

# 策略选择器
class DiscountCalculator:
    def __init__(self):
        self.strategies = {
            "vip": PercentageDiscount(20),
            "new_user": FixedDiscount(50),
            "promotion": BuyOneGetOneFree(),
            "none": NoDiscount(),
        }
    
    def calculate(self, user_type, amount):
        strategy = self.strategies.get(user_type, self.strategies["none"])
        return strategy.calculate(amount)

# 使用
calc = DiscountCalculator()
print(f"VIP用户 200元 → 实付{calc.calculate('vip', 200)}元")
print(f"新用户 200元 → 实付{calc.calculate('new_user', 200)}元")

4.4 提前返回法

# ❌ 深度嵌套的if-elif
def validate_user_bad(user):
    if user is not None:
        if user.get("name"):
            if user.get("email"):
                if "@" in user["email"]:
                    if user.get("age", 0) >= 18:
                        return True, "验证通过"
                    else:
                        return False, "未满18岁"
                else:
                    return False, "邮箱格式不正确"
            else:
                return False, "邮箱不能为空"
        else:
            return False, "用户名不能为空"
    else:
        return False, "用户不存在"

# ✅ 提前返回,扁平化
def validate_user_good(user):
    if user is None:
        return False, "用户不存在"
    if not user.get("name"):
        return False, "用户名不能为空"
    if not user.get("email"):
        return False, "邮箱不能为空"
    if "@" not in user["email"]:
        return False, "邮箱格式不正确"
    if user.get("age", 0) < 18:
        return False, "未满18岁"
    return True, "验证通过"

五、条件表达式的组合与简化

5.1 多条件组合

# 使用 and、or、not 组合条件
def can_enter_club(person):
    """判断是否可以进入俱乐部"""
    # 组合多个条件
    if person.get("age", 0) >= 18 and not person.get("is_banned") and \
       (person.get("is_member") or person.get("has_invitation")):
        return True
    return False

# 更好的写法:拆分为多个变量
def can_enter_club_v2(person):
    is_adult = person.get("age", 0) >= 18
    is_not_banned = not person.get("is_banned", False)
    has_access = person.get("is_member") or person.get("has_invitation")
    
    return is_adult and is_not_banned and has_access

5.2 利用德摩根定律简化条件

# 德摩根定律:
# not (A and B) = (not A) or (not B)
# not (A or B)  = (not A) and (not B)

# 原始条件(读起来费劲)
if not (user is None or user.get("is_banned")):
    allow_access()

# 应用德摩根定律
if user is not None and not user.get("is_banned"):
    allow_access()

# 另一个例子
# 原始
if not (age < 18 or age > 65):
    charge_full_price()

# 简化
if 18 <= age <= 65:
    charge_full_price()

5.3 all() 和 any() 简化多条件

# 当需要检查多个条件时

# ❌ 冗长的 and 链
if form.get("name") and form.get("email") and form.get("phone") and \
   form.get("address") and form.get("city"):
    print("所有字段都已填写")

# ✅ 使用 all()
required_fields = ["name", "email", "phone", "address", "city"]
if all(form.get(field) for field in required_fields):
    print("所有字段都已填写")

# ❌ 冗长的 or 链
if status == "error" or status == "fail" or status == "rejected" or \
   status == "denied" or status == "cancelled":
    print("操作未成功")

# ✅ 使用 any() 或 in
FAIL_STATUSES = {"error", "fail", "rejected", "denied", "cancelled"}
if status in FAIL_STATUSES:
    print("操作未成功")

六、实战案例

6.1 电商订单状态机

class OrderStateMachine:
    """订单状态机 —— if-elif-else 的典型应用"""
    
    # 状态转换规则
    TRANSITIONS = {
        "pending": ["paid", "cancelled"],
        "paid": ["shipped", "refunding"],
        "shipped": ["delivered", "returning"],
        "delivered": ["completed"],
        "refunding": ["refunded"],
        "returning": ["returned"],
        "completed": [],
        "cancelled": [],
        "refunded": [],
        "returned": [],
    }
    
    @classmethod
    def can_transition(cls, from_status, to_status):
        """检查状态转换是否合法"""
        allowed = cls.TRANSITIONS.get(from_status, [])
        return to_status in allowed
    
    @classmethod
    def transition(cls, order, to_status):
        """执行状态转换"""
        current = order.get("status", "pending")
        
        if not cls.can_transition(current, to_status):
            return False, f"不允许从 {current} 转换到 {to_status}"
        
        # 根据目标状态执行不同的操作
        if to_status == "paid":
            success = cls._process_payment(order)
        elif to_status == "shipped":
            success = cls._create_shipment(order)
        elif to_status == "delivered":
            success = cls._confirm_delivery(order)
        elif to_status == "cancelled":
            success = cls._cancel_order(order)
        elif to_status == "refunding":
            success = cls._initiate_refund(order)
        elif to_status == "completed":
            success = cls._complete_order(order)
        else:
            success = True
        
        if success:
            order["status"] = to_status
            return True, f"订单状态: {current} → {to_status}"
        else:
            return False, "操作执行失败"
    
    @staticmethod
    def _process_payment(order):
        print(f"  处理支付: 订单{order['id']}, 金额{order['amount']}")
        return True
    
    @staticmethod
    def _create_shipment(order):
        print(f"  创建发货单: 订单{order['id']}")
        return True
    
    @staticmethod
    def _confirm_delivery(order):
        print(f"  确认收货: 订单{order['id']}")
        return True
    
    @staticmethod
    def _cancel_order(order):
        print(f"  取消订单: 订单{order['id']}")
        return True
    
    @staticmethod
    def _initiate_refund(order):
        print(f"  发起退款: 订单{order['id']}")
        return True
    
    @staticmethod
    def _complete_order(order):
        print(f"  完成订单: 订单{order['id']}")
        return True

# 测试
order = {"id": "ORD-001", "amount": 299.00, "status": "pending"}
print(f"初始状态: {order['status']}")

success, msg = OrderStateMachine.transition(order, "paid")
print(f"  {msg}")

success, msg = OrderStateMachine.transition(order, "shipped")
print(f"  {msg}")

success, msg = OrderStateMachine.transition(order, "cancelled")
print(f"  {msg}")  # 不允许从 shipped 直接取消

6.2 智能客服路由系统

class TicketRouter:
    """工单路由系统 —— 复杂多条件分支"""
    
    # 部门和优先级定义
    DEPARTMENTS = {
        "tech": "技术支持部",
        "billing": "财务部",
        "sales": "销售部",
        "hr": "人力资源部",
        "general": "综合服务部",
    }
    
    PRIORITIES = {
        "urgent": 0,
        "high": 1,
        "normal": 2,
        "low": 3,
    }
    
    @classmethod
    def route(cls, ticket):
        """根据工单内容路由到合适的部门和优先级"""
        subject = ticket.get("subject", "").lower()
        body = ticket.get("body", "").lower()
        user_type = ticket.get("user_type", "normal")
        full_text = subject + " " + body
        
        department = "general"
        priority = "normal"
        
        # --- 确定优先级 ---
        # VIP用户工单优先级最高
        if user_type == "vip":
            priority = "high"
        
        # 紧急关键词
        urgent_keywords = ["down", "宕机", "无法访问", "数据丢失", "安全漏洞", "紧急", "urgent"]
        if any(kw in full_text for kw in urgent_keywords):
            priority = "urgent"
        
        # SLA过期自动升级
        if ticket.get("sla_hours", 0) > 48:
            if priority == "normal":
                priority = "high"
            elif priority == "low":
                priority = "normal"
        
        # --- 确定部门 ---
        # 技术问题
        tech_keywords = ["bug", "error", "错误", "报错", "崩溃", "crash", "api", "接口",
                         "慢", "timeout", "超时", "部署", "deploy", "数据库", "database"]
        billing_keywords = ["退款", "refund", "发票", "invoice", "账单", "bill", "费用",
                            "扣款", "支付", "payment", "余额", "balance"]
        sales_keywords = ["试用", "trial", "购买", "purchase", "升级", "upgrade", "报价",
                          "quote", "演示", "demo"]
        hr_keywords = ["入职", "onboarding", "离职", "offboarding", "权限", "access"]
        
        # 部门匹配(优先级从高到低)
        if any(kw in full_text for kw in tech_keywords):
            department = "tech"
        elif any(kw in full_text for kw in billing_keywords):
            department = "billing"
        elif any(kw in full_text for kw in sales_keywords):
            department = "sales"
        elif any(kw in full_text for kw in hr_keywords):
            department = "hr"
        else:
            department = "general"
        
        return {
            "department": cls.DEPARTMENTS[department],
            "department_code": department,
            "priority": priority,
            "priority_level": cls.PRIORITIES[priority],
        }

# 测试
tickets = [
    {"subject": "系统宕机了!", "body": "生产环境全部无法访问", "user_type": "vip"},
    {"subject": "退款申请", "body": "上个月的账单有问题,要求退款", "user_type": "normal"},
    {"subject": "想了解企业版", "body": "我们需要500人版本,请给报价", "user_type": "normal"},
    {"subject": "API返回500错误", "body": "调用/user接口一直报错", "user_type": "normal"},
]

for i, ticket in enumerate(tickets, 1):
    result = TicketRouter.route(ticket)
    print(f"\n工单{i}: {ticket['subject']}")
    print(f"  部门: {result['department']}")
    print(f"  优先级: {result['priority']} (级别{result['priority_level']})")

6.3 游戏技能伤害计算器

class DamageCalculator:
    """游戏技能伤害计算 —— 多因素条件判断"""
    
    ELEMENT_CHART = {
        # 攻击属性: {防御属性: 伤害倍率}
        "fire":  {"water": 0.5, "grass": 2.0, "fire": 1.0, "earth": 1.0, "wind": 1.0},
        "water": {"fire": 2.0, "grass": 0.5, "water": 1.0, "earth": 1.5, "wind": 0.75},
        "grass": {"water": 2.0, "fire": 0.5, "grass": 1.0, "earth": 2.0, "wind": 0.5},
        "earth": {"fire": 1.5, "water": 0.5, "grass": 0.5, "earth": 1.0, "wind": 0.5},
        "wind":  {"fire": 1.0, "water": 1.5, "grass": 1.5, "earth": 1.0, "wind": 1.0},
    }
    
    @classmethod
    def calculate(cls, attacker, defender, skill):
        """计算最终伤害"""
        base_damage = skill["power"]
        
        # 1. 属性克制
        element_multiplier = 1.0
        if "element" in skill and "element" in defender:
            element_multiplier = cls.ELEMENT_CHART.get(
                skill["element"], {}
            ).get(defender["element"], 1.0)
        
        if element_multiplier >= 2.0:
            print("  🔥 属性克制!效果拔群!")
        elif element_multiplier <= 0.5:
            print("  💧 属性抵抗!效果不佳...")
        
        # 2. 暴击判断
        crit_multiplier = 1.0
        crit_rate = attacker.get("crit_rate", 0.05)
        import random
        if random.random() < crit_rate:
            crit_multiplier = attacker.get("crit_damage", 1.5)
            print(f"  ⚡ 暴击!伤害×{crit_multiplier}")
        
        # 3. 防御减免
        defense = defender.get("defense", 0)
        defense_reduction = defense / (defense + 100)  # 标准防御公式
        damage_multiplier = 1 - defense_reduction
        
        # 4. 增益/减益效果
        if attacker.get("attack_buff"):
            damage_multiplier *= 1.5
            print("  💪 攻击提升!")
        if defender.get("defense_buff"):
            damage_multiplier *= 0.67
            print("  🛡️ 防御提升!")
        if attacker.get("weakened"):
            damage_multiplier *= 0.5
            print("  😵 攻击者虚弱中...")
        
        # 5. 等级差修正
        level_diff = attacker.get("level", 1) - defender.get("level", 1)
        if level_diff > 10:
            damage_multiplier *= 1.25
            print("  ⬆️ 等级压制!")
        elif level_diff < -10:
            damage_multiplier *= 0.75
            print("  ⬇️ 等级劣势!")
        
        # 最终伤害
        final_damage = base_damage * element_multiplier * crit_multiplier * damage_multiplier
        final_damage = max(1, int(final_damage))  # 最少造成1点伤害
        
        return final_damage

# 测试
attacker = {"level": 50, "crit_rate": 0.3, "crit_damage": 2.0, "attack_buff": True}
defender = {"level": 40, "defense": 80, "element": "grass", "defense_buff": False}
skill = {"name": "火焰冲击", "power": 200, "element": "fire"}

print(f"{skill['name']} → 目标属性: {defender['element']}")
damage = DamageCalculator.calculate(attacker, defender, skill)
print(f"最终伤害: {damage}点")

七、本章小结

本文我们深入学习了if-elif-else多条件分支的全面知识:

掌握if-elif-else不仅是掌握一个语法,更是掌握一种结构化决策的思维方式。当你能用清晰、高效、可维护的方式表达复杂的业务规则时,你就真正掌握了这门艺术。⌨️ 下一篇文章,我们将学习条件判断的嵌套与多条件组合写法。

到此这篇关于Python基础指南之if-elif-else多条件分支全面解析的文章就介绍到这了,更多相关Python if-elif-else多条件分支内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文