match / case: pattern matching estructural (Python 3.10+)
match/case no es solo un switch mejorado: es un sistema completo de pattern matching que puede desestructurar listas, dicts y objetos con una sintaxis elegante.
Sintaxis básica
match/case fue introducido en Python 3.10. A diferencia de switch en otros lenguajes, puede desestructurar valores complejos, no solo comparar literales:
def describir_numero(n):
match n:
case 0:
return "cero"
case 1:
return "uno"
case 2 | 3: # OR de patrones con |
return "dos o tres"
case n if n < 0: # guarda (guard) con if
return f"negativo: {n}"
case _: # comodín (siempre al final)
return f"otro número: {n}"
print(describir_numero(0)) # cero
print(describir_numero(2)) # dos o tres
print(describir_numero(-5)) # negativo: -5
print(describir_numero(100)) # otro número: 100
cero
dos o tres
negativo: -5
otro número: 100El guion bajo _ en case _: es el comodín que coincide con cualquier valor sin capturarlo. Es el equivalente al default: del switch de otros lenguajes.
Patrones de secuencia y mapeo
Aquí es donde match/case supera ampliamente al switch: puede desestructurar listas, tuplas y diccionarios directamente en el patrón:
def analizar_comando(comando):
"""Parsea una lista de tokens de una CLI."""
match comando:
case []:
return "Sin argumentos"
case ["quit"] | ["exit"]:
return "Saliendo..."
case ["ir", destino]:
return f"Yendo a: {destino}"
case ["ir", destino, *resto]:
return f"Yendo a {destino} con opciones: {resto}"
case ["ayuda", tema, *_]:
return f"Mostrando ayuda sobre: {tema}"
case _:
return f"Comando desconocido: {comando}"
print(analizar_comando([]))
print(analizar_comando(["quit"]))
print(analizar_comando(["ir", "inicio"]))
print(analizar_comando(["ir", "sala", "--rapido", "--silencioso"]))
Sin argumentos
Saliendo...
Yendo a: inicio
Yendo a sala con opciones: ['--rapido', '--silencioso']def procesar_evento(evento):
"""Procesa eventos de un sistema de notificaciones."""
match evento:
case {"tipo": "click", "elemento": elemento}:
return f"Click en: {elemento}"
case {"tipo": "scroll", "delta": delta} if delta > 0:
return f"Scroll arriba: {delta}px"
case {"tipo": "scroll", "delta": delta}:
return f"Scroll abajo: {abs(delta)}px"
case {"tipo": tipo, **resto}:
return f"Evento desconocido: {tipo}, datos: {resto}"
case _:
return "Evento inválido"
print(procesar_evento({"tipo": "click", "elemento": "boton-enviar"}))
print(procesar_evento({"tipo": "scroll", "delta": 120}))
print(procesar_evento({"tipo": "tecla", "codigo": 13}))
Click en: boton-enviar
Scroll arriba: 120px
Evento desconocido: tecla, datos: {'codigo': 13}Guardas (if en case)
Una guarda es una condición if adicional que debe ser verdadera para que el case coincida. El patrón se evalúa primero; si coincide, se evalúa la guarda:
def clasificar_punto(punto):
"""Clasifica un punto (x, y) en el plano cartesiano."""
match punto:
case (0, 0):
return "Origen"
case (x, 0):
return f"Eje X en x={x}"
case (0, y):
return f"Eje Y en y={y}"
case (x, y) if x > 0 and y > 0:
return f"Cuadrante I: ({x}, {y})"
case (x, y) if x < 0 and y > 0:
return f"Cuadrante II: ({x}, {y})"
case (x, y) if x < 0 and y < 0:
return f"Cuadrante III: ({x}, {y})"
case (x, y):
return f"Cuadrante IV: ({x}, {y})"
print(clasificar_punto((0, 0))) # Origen
print(clasificar_punto((5, 0))) # Eje X en x=5
print(clasificar_punto((3, 4))) # Cuadrante I: (3, 4)
print(clasificar_punto((-1, -2))) # Cuadrante III: (-1, -2)
Origen
Eje X en x=5
Cuadrante I: (3, 4)
Cuadrante III: (-1, -2)Cuándo usarlo vs if/elif
| Usa match/case | Usa if/elif |
|---|---|
| Cuando el valor puede tener varias formas estructurales distintas | Cuando las condiciones son expresiones booleanas complejas |
| Cuando desestructuras listas, tuplas o dicts en el patrón | Cuando comparas rangos numéricos (edad >= 18 and edad < 65) |
| Cuando procesas mensajes, comandos o eventos tipados | Cuando las condiciones involucran múltiples variables no relacionadas |
| No disponible antes de Python 3.10 | Funciona en todas las versiones de Python 3 |
A diferencia del switch de C, Java o JavaScript, match/case no tiene fallthrough (no necesitas break). Solo el primer case que coincide se ejecuta.
Practica
Tres ejercicios para dominar el pattern matching de Python.