什么时候你可以用 match-case 而不是 if-else?

什么时候你可以用 match-case 而不是 if-else?

Published on

目录:


match-case 真香,且无法被 if-else 平替。

1️⃣ 场景①:多值组合匹配
👇把 3 个布尔值所有排列组合一次写清

def check(a, b, c):
    match (a, b, c):
        case (True,  True,  True):  print("全开")
        case (False, False, False): print("全关")
        case (True,  _,     _):     print("A 开,其余随意")
        case _:                     print("其他")

✅ 一行一个模式,一眼就知道漏了谁。
❌ 用 if-else 要写 8 个 elif,还得自己数括号。


2️⃣ 场景②:结构解包 + 类型匹配
👇解析 JSON 风格数据,只关心关键字段

match data:
    case {"type": "point", "x": 0, "y": y}:        print(f"Y 轴点,y={y}")
    case {"type": "circle", "radius": r} if r > 0: print(f"合法圆,半径{r}")
    case _:                                        print("不认识")

✅ 直接把字典结构画出来,变量一起解包。
❌ if-else 得先判断字段是否存在,再提取,再转型,5 行起步。


3️⃣ 场景③:代码自文档 = 可读性 MAX
👇看这段 HTTP 状态码处理,谁更友好?

# match 版
match status:
    case 200 | 201: print("成功")
    case 404:       print("找不到")
    case 500..599:  print("服务器错误")
    case int() as s if s >= 400: print("客户端错误")
    case _:         print("其他")

✅ 像读表格一样读代码。
❌ if-elif 版全是 andor,新人来了一脸懵。


🎯 一句话总结
“只要你在写多分支+结构/类型/组合——
别纠结,match-case 就是 Python 给你的语法糖。”

下面一次性给你 6 个日常最容易写成 “if-else 地狱” 的典型片段,全部都配好了可直接替换的 match-case 版本。复制就能用,也欢迎你在评论区继续贴代码,我随时在线改!


🔥 地狱 1:命令分发器

# before
if cmd == "start":
    start()
elif cmd == "stop":
    stop()
elif cmd == "restart":
    restart()
elif cmd in ("reload", "refresh"):
    reload()
else:
    unknown(cmd)

# after
match cmd:
    case "start":   start()
    case "stop":    stop()
    case "restart": restart()
    case "reload" | "refresh": reload()
    case _:         unknown(cmd)

🔥 地狱 2:HTTP 状态码归类

# before
if 200 <= code < 300:
    return "success"
elif 400 <= code < 500:
    return "client_error"
elif 500 <= code < 600:
    return "server_error"
else:
    return "unknown"

# after
match code:
    case int() as c if 200 <= c < 300: return "success"
    case int() as c if 400 <= c < 500: return "client_error"
    case int() as c if 500 <= c < 600: return "server_error"
    case _: return "unknown"

🔥 地狱 3:解析嵌套列表

# before
if isinstance(data, list) and len(data) == 3:
    a, b, c = data
    if isinstance(b, str) and c is None:
        handle(a, b)
    elif isinstance(b, int) and isinstance(c, list):
        handle2(a, b, c)
else:
    fallback()

# after
match data:
    case [a, str(b), None]:
        handle(a, b)
    case [a, int(b), list(c)]:
        handle2(a, b, c)
    case _:
        fallback()

🔥 地狱 4:枚举+数据打包

# before
if op == "add":
    result = a + b
elif op == "sub":
    result = a - b
elif op == "mul":
    result = a * b
elif op == "div":
    if b == 0:
        raise ZeroDivisionError
    result = a / b

# after
match (op, a, b):
    case ("add", _, _):           result = a + b
    case ("sub", _, _):           result = a - b
    case ("mul", _, _):           result = a * b
    case ("div", _, 0):           raise ZeroDivisionError
    case ("div", _, _):           result = a / b
    case _:                       raise ValueError("unknown op")

🔥 地狱 5:日志级别过滤

# before
if level == "DEBUG":
    logger.debug(msg)
elif level == "INFO":
    logger.info(msg)
elif level == "WARNING":
    logger.warning(msg)
elif level in ("ERROR", "FATAL"):
    logger.error(msg)

# after
match level.upper():
    case "DEBUG":   logger.debug(msg)
    case "INFO":    logger.info(msg)
    case "WARNING": logger.warning(msg)
    case "ERROR" | "FATAL": logger.error(msg)

🔥 地狱 6:类实例的多态判断

# before
if isinstance(obj, Circle):
    area = 3.14 * obj.radius ** 2
elif isinstance(obj, Rectangle):
    area = obj.width * obj.height
elif isinstance(obj, Triangle):
    area = 0.5 * obj.base * obj.height

# after
from shapes import Circle, Rectangle, Triangle
match obj:
    case Circle(radius=r):       area = 3.14 * r ** 2
    case Rectangle(w=w, h=h):    area = w * h
    case Triangle(b=base, h=h):  area = 0.5 * base * h
    case _: raise TypeError("unknown shape")