Python & AI Tutorials Logo
Programación Python

13. Tomar decisiones con match y case (Structural Pattern Matching)

Cuando tu programa necesita tomar decisiones basadas en múltiples valores o patrones posibles, ya has aprendido a usar cadenas if-elif-else del Capítulo 8. Python 3.10 introdujo una alternativa potente llamada structural pattern matching usando sentencias match y case. Esta característica proporciona una forma más limpia y expresiva de manejar escenarios complejos de toma de decisiones.

El pattern matching va más allá de simples comparaciones de valores. Te permite hacer coincidencias contra la estructura y la forma de los datos, extraer valores de objetos complejos y expresar decisiones con múltiples caminos en un formato más legible. Aunque las cadenas if-elif-else funcionan perfectamente bien para muchas situaciones, las sentencias match-case brillan cuando estás lidiando con múltiples casos distintos, especialmente al trabajar con datos estructurados.

13.1) Introducción a las sentencias match y case (Basándose en if-elif del Capítulo 8)

13.1.1) La estructura básica de match-case

Una sentencia match examina un valor (llamado el sujeto) y lo compara con uno o más patrones(patterns) definidos en cláusulas case. Cuando un patrón coincide, Python ejecuta el bloque de código asociado con ese caso.

Esta es la estructura básica:

python
match subject:
    case pattern1:
        # Código a ejecutar si pattern1 coincide
    case pattern2:
        # Código a ejecutar si pattern2 coincide
    case pattern3:
        # Código a ejecutar si pattern3 coincide

Empecemos con un ejemplo simple que demuestra el concepto fundamental:

python
# Manejador simple de códigos de estado HTTP
status_code = 404
 
match status_code:
    case 200:
        print("Success: Request completed")
    case 404:
        print("Error: Page not found")
    case 500:
        print("Error: Server error")

Output:

Error: Page not found

En este ejemplo, la sentencia match examina status_code (el sujeto). Python comprueba cada patrón de case en orden. Cuando encuentra que status_code es igual a 404, ejecuta el bloque de código correspondiente y luego sale de la sentencia match. Los casos restantes no se comprueban.

13.1.2) En qué se diferencia match-case de if-elif-else

Puede que te preguntes: "¿No podría escribir esto con if-elif-else?" Sí, podrías:

python
status_code = 404
 
if status_code == 200:
    print("Success: Request completed")
elif status_code == 404:
    print("Error: Page not found")
elif status_code == 500:
    print("Error: Server error")

Output:

Error: Page not found

Ambas versiones producen el mismo resultado. Sin embargo, match-case ofrece varias ventajas:

  1. Intención más clara: La sentencia match muestra explícitamente que estás comprobando un valor contra múltiples posibilidades
  2. Menos repetición: No repites el nombre de la variable en cada comparación
  3. Patrones(patterns) más potentes: Como veremos, match-case puede hacer mucho más que simples comprobaciones de igualdad
  4. Mejor legibilidad: Para árboles de decisión complejos, match-case suele ser más fácil de entender

13.1.3) Cuando ningún patrón coincide

¿Qué pasa si ninguno de los patrones coincide? La sentencia match simplemente termina sin ejecutar ningún bloque de caso:

python
# Verificador de rol de usuario
user_role = "guest"
 
match user_role:
    case "admin":
        print("Full system access granted")
    case "moderator":
        print("Content management access granted")
    case "editor":
        print("Editing access granted")
 
print("Role check complete")

Output:

Role check complete

Como "guest" no coincide con ninguno de los patrones, no se ejecuta ningún bloque case. El programa continúa con el código después de la sentencia match. Este comportamiento es importante de entender: a diferencia de las cadenas if-elif-else donde puedes añadir una cláusula final else para capturar todos los demás casos, una sentencia match básica sin un patrón que lo abarque todo no hará nada silenciosamente si ningún patrón coincide.

13.1.4) Ejemplo práctico: Sistema de selección de menú

Construyamos un ejemplo más completo que demuestre la claridad de match-case para manejar elecciones del usuario:

python
# Sistema de pedidos de restaurante
menu_choice = 3
 
match menu_choice:
    case 1:
        item = "Caesar Salad"
        price = 8.99
        print(f"You ordered: {item} - ${price}")
    case 2:
        item = "Grilled Chicken"
        price = 14.99
        print(f"You ordered: {item} - ${price}")
    case 3:
        item = "Vegetable Pasta"
        price = 12.99
        print(f"You ordered: {item} - ${price}")
    case 4:
        item = "Chocolate Cake"
        price = 6.99
        print(f"You ordered: {item} - ${price}")
 
print("Order submitted to kitchen")

Output:

You ordered: Vegetable Pasta - $12.99
Order submitted to kitchen

Este ejemplo muestra cómo cada caso puede contener múltiples sentencias. Cuando menu_choice coincide con 3, Python ejecuta las tres líneas en ese bloque de caso: asignar item, asignar price e imprimir la confirmación del pedido.

13.2) Usar el comodín _, patrones literales y múltiples patrones

13.2.1) El patrón comodín: capturar todo lo demás

El guion bajo _ es un patrón especial que coincide con cualquier cosa. Normalmente se usa como el último caso para manejar todos los valores que no coincidieron con los patrones anteriores, similar a una cláusula else final en una cadena if-elif-else:

python
# Manejador de códigos de estado HTTP con caso por defecto
status_code = 403
 
match status_code:
    case 200:
        print("Success: Request completed")
    case 404:
        print("Error: Page not found")
    case 500:
        print("Error: Server error")
    case _:
        print(f"Unhandled status code: {status_code}")

Output:

Unhandled status code: 403

El patrón _ actúa como un comodín. Como 403 no coincide con ninguno de los casos específicos, el patrón comodín coincide y ejecuta su bloque. El patrón comodín coincidirá con cualquier valor, así que siempre debería colocarse al final: cualquier caso posterior nunca se ejecutaría.

Aquí tienes por qué el comodín es útil en la práctica:

python
# Planificador de días de la semana
day = "Saturday"
 
match day:
    case "Monday":
        print("Team meeting at 9 AM")
    case "Wednesday":
        print("Project review at 2 PM")
    case "Friday":
        print("Weekly report due")
    case _:
        print(f"{day}: No scheduled events")

Output:

Saturday: No scheduled events

Sin el patrón comodín, si day fuera "Saturday", "Sunday" o cualquier otro valor, la sentencia match terminaría silenciosamente sin salida. El comodín asegura que manejas casos inesperados o no especificados de forma elegante.

13.2.2) Patrones literales: coincidir con valores específicos

Los patrones literales(literal patterns) coinciden con valores exactos. Ya los hemos estado usando: los números, cadenas y valores booleanos son todos patrones literales:

python
# Controlador de semáforo
light_color = "yellow"
 
match light_color:
    case "green":
        print("Go")
    case "yellow":
        print("Caution: Light changing soon")
    case "red":
        print("Stop")
    case _:
        print("Invalid light color")

Output:

Caution: Light changing soon

Puedes usar patrones literales de distintos tipos, y match compara tanto el valor como su tipo:

python
# Validador de configuración (usando distintos tipos literales)
setting_value = True
 
match setting_value:
    case True:        # literal booleano
        print("Feature enabled")
    case False:       # literal booleano
        print("Feature disabled")
    case None:        # literal None
        print("Feature not configured")
    case 0:           # literal entero
        print("Feature explicitly turned off")
    case "auto":      # literal de cadena
        print("Feature set to automatic mode")
    case _:
        print("Invalid configuration value")

Output:

Feature enabled

Los patrones literales funcionan con enteros, floats, cadenas, booleanos y None. Python comprueba la igualdad usando las mismas reglas que el operador ==.

13.2.3) Múltiples patrones con el operador OR

A veces quieres ejecutar el mismo código para varios valores distintos. Puedes combinar múltiples patrones usando el operador | (pipe), que significa "o":

python
# Detector de fin de semana
day = "Saturday"
 
match day:
    case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
        print("It's a weekday - time to work!")
    case "Saturday" | "Sunday":
        print("It's the weekend - time to relax!")
    case _:
        print("Invalid day name")

Output:

It's the weekend - time to relax!

El operador | te permite especificar múltiples patrones que deberían desencadenar la misma acción. Si el sujeto coincide con cualquiera de los patrones separados por |, se ejecuta ese caso. Esto es mucho más limpio que escribir casos separados con bloques de código idénticos.

Puedes mezclar distintos tipos de patrones con |:

python
# Validador de entrada para preguntas de sí/no
response = "yes"
 
match response:
    case True | "yes":
        print("You confirmed the action")
    case False | "no":
        print("You cancelled the action")
    case _:
        print("Please answer yes or no")

Output:

You confirmed the action

13.2.4) Capturar qué alternativa coincidió con as

Al usar múltiples patrones con |, puede que quieras saber qué valor específico coincidió. Puedes usar la palabra clave as para capturar el valor coincidente:

python
# Manejador de códigos de estado con respuestas agrupadas
status = 201
 
match status:
    case 200 | 201 | 202 | 204 as success_code:
        print(f"Success: {success_code}")
    case 400 | 401 | 403 | 404 as client_error:
        print(f"Client error: {client_error}")
    case 500 | 502 | 503 as server_error:
        print(f"Server error: {server_error}")
    case _:
        print("Unknown status code")

Output:

Success: 201

La palabra clave as crea una variable de enlace que captura la alternativa que haya coincidido. En este ejemplo, success_code queda enlazada a 201 porque ese es el valor específico que coincidió de las alternativas 200 | 201 | 202 | 204.

Aquí tienes otro ejemplo que muestra cómo esto es útil para el logging:

python
# Procesador de nivel de log
log_level = "WARN"
 
match log_level:
    case "DEBUG" | "TRACE" as level:
        print(f"Verbose logging: {level}")
        print("Detailed diagnostic information will be recorded")
    case "INFO" | "NOTICE" as level:
        print(f"Informational: {level}")
        print("Normal operation messages will be recorded")
    case "WARN" | "WARNING" as level:
        print(f"Warning level: {level}")
        print("Potential issues detected")
    case "ERROR" | "FATAL" | "CRITICAL" as level:
        print(f"Error level: {level}")
        print("Immediate attention required")
    case _:
        print("Unknown log level")

Output:

Warning level: WARN
Potential issues detected

13.3) Extraer valores con variables de enlace

13.3.1) ¿Qué son las variables de enlace?

Hasta ahora, hemos hecho coincidencias contra valores literales. Pero el pattern matching se vuelve realmente potente cuando puedes capturar o extraer partes de los datos con los que haces la coincidencia. Una variable de enlace(binding variable) (también llamada un patrón de captura(capture pattern)) es un nombre en un patrón que captura el valor coincidente y lo pone a disposición dentro del bloque del caso.

Aquí tienes un ejemplo simple:

python
# Captura simple de valor
command = "save"
 
match command:
    case "quit":
        print("Exiting program")
    case action:  # Esta es una variable de enlace
        print(f"Executing action: {action}")

Output:

Executing action: save

El patrón action es una variable de enlace. Coincide con cualquier valor (como el comodín _), pero a diferencia de _, captura ese valor y lo asigna al nombre action. Dentro del bloque del caso, puedes usar action para referirte al valor coincidente.

Distinción importante: Una variable de enlace coincide con cualquier cosa, igual que _. La diferencia es que _ descarta el valor, mientras que una variable de enlace lo captura para usarlo dentro del bloque del caso.

13.3.2) Variables de enlace vs comodines

Comparemos las variables de enlace y los comodines directamente:

python
# Usando comodín: el valor no se captura
status = 403
 
match status:
    case 200:
        print("Success")
    case _:
        print("Some other status code")  # No puedes acceder al valor real

Output:

Some other status code

Ahora con una variable de enlace:

python
# Usando variable de enlace: el valor se captura
status = 403
 
match status:
    case 200:
        print("Success")
    case code:  # La variable de enlace captura el valor
        print(f"Status code {code} received")

Output:

Status code 403 received

La variable de enlace code captura el valor 403, haciéndolo disponible dentro del bloque del caso. Esto es útil cuando necesitas trabajar con el valor real que no coincidió con tus patrones específicos.

13.3.3) Coincidir patrones de tuplas y extraer componentes

El pattern matching se vuelve especialmente potente con datos estructurados como las tuplas. Puedes coincidir con la forma de una tupla y extraer sus componentes simultáneamente. Aunque estudiaremos las tuplas en detalle en el Capítulo 15, este ejemplo se centra solo en cómo funcionan los patrones de tuplas en sentencias match.

python
# Sistema de coordenadas: coincidencia con un patrón de tupla
point = (3, 7)
 
match point:
    case (0, 0):
        print("Origin point")
    case (0, y):  # Coincide con cualquier punto sobre el eje y
        print(f"On y-axis at y={y}")
    case (x, 0):  # Coincide con cualquier punto sobre el eje x
        print(f"On x-axis at x={x}")
    case (x, y):  # Coincide con cualquier otro punto
        print(f"Point at coordinates ({x}, {y})")

Output:

Point at coordinates (3, 7)

Desglosemos lo que está pasando:

  1. El sujeto point es la tupla (3, 7)
  2. Python comprueba cada patrón de caso en orden
  3. Los tres primeros patrones no coinciden porque requieren el valor 0 en una posición específica, y la tupla (3, 7) no tiene ningún elemento igual a 0
  4. El patrón (x, y) coincide porque es una tupla de dos elementos
  5. Python enlaza x a 3 e y a 7
  6. El bloque del caso se ejecuta con estos valores capturados

Aquí tienes otro ejemplo que muestra distintos patrones de tuplas:

python
# Analizador de color RGB
color = (255, 0, 0)
 
match color:
    case (0, 0, 0):
        print("Black")
    case (255, 255, 255):
        print("White")
    case (r, 0, 0):  # Rojo puro con intensidad variable
        print(f"Pure red with intensity {r}")
    case (0, g, 0):  # Verde puro
        print(f"Pure green with intensity {g}")
    case (0, 0, b):  # Azul puro
        print(f"Pure blue with intensity {b}")
    case (r, g, b):  # Cualquier otro color
        print(f"RGB color: red={r}, green={g}, blue={b}")

Output:

Pure red with intensity 255

Esta entrada coincide con el patrón (r, 0, 0) porque la tupla tiene tres elementos, los dos últimos son 0, y el primer valor queda enlazado a r.

13.3.4) Coincidir patrones de listas

También puedes coincidir con patrones de listas y extraer elementos. Cubriremos las listas en detalle en el Capítulo 14; por ahora, este ejemplo se centra en cómo funcionan los patrones de listas en sentencias match:

python
# Comando con argumentos
command = ["move", "north", "5"]
 
match command:
    case ["quit"]:
        print("Exiting game")
    case ["look"]:
        print("You look around the room")
    case ["move", direction]:
        print(f"Moving {direction}")
    case ["move", direction, distance]:
        print(f"Moving {direction} for {distance} steps")
    case _:
        print("Unknown command")

Output:

Moving north for 5 steps

El patrón ["move", direction, distance] coincide con una lista de tres elementos donde el primer elemento es "move". Captura el segundo elemento como direction y el tercero como distance.

Aquí tienes un ejemplo práctico con longitudes de lista variables:

python
# Procesador de artículos del carrito de compra
item = ["laptop", 999.99, 2]
 
match item:
    case [name]:  # Artículo con solo un nombre
        print(f"Item: {name} (no price or quantity specified)")
    case [name, price]:  # Artículo con nombre y precio
        print(f"Item: {name}, Price: ${price}, Quantity: 1 (default)")
    case [name, price, quantity]:  # Información completa del artículo
        total = price * quantity
        print(f"Item: {name}, Price: ${price}, Quantity: {quantity}")
        print(f"Subtotal: ${total}")
    case _:
        print("Invalid item format")

Output:

Item: laptop, Price: $999.99, Quantity: 2
Subtotal: $1999.98

El caso [name, price, quantity] se ejecuta porque la lista tiene exactamente tres elementos, y cada elemento queda enlazado a su variable correspondiente.

13.3.5) Coincidir patrones de diccionarios

El pattern matching funciona también con diccionarios, lo que te permite hacer coincidencias con claves específicas y extraer sus valores. Aunque estudiaremos los diccionarios en detalle en el Capítulo 16, esta sección se centra solo en cómo funcionan los patrones de diccionarios en sentencias match.

python
# Procesador de perfil de usuario
user = {"name": "Alice", "role": "admin", "active": True}
 
match user:
    case {"role": "admin", "active": True}:
        print("Active administrator - full access granted")
    case {"role": "admin", "active": False}:
        print("Inactive administrator - access suspended")
    case {"role": role, "active": True}:  # Captura el valor de role
        print(f"Active user with role: {role}")
    case {"role": role, "active": False}:
        print(f"Inactive user with role: {role}")
    case _:
        print("Invalid user profile")

Output:

Active administrator - full access granted

El caso {"role": "admin", "active": True} se ejecuta porque los patrones de diccionario requieren coincidir con pares clave–valor, y esta coincidencia exacta se comprueba antes que patrones más generales.

Los patrones de diccionario son flexibles: coinciden si las claves especificadas existen con los valores especificados, incluso si el diccionario tiene claves adicionales:

python
# Manejador de respuesta de API
response = {"status": "success", "data": {"id": 123, "name": "Product"}, "timestamp": "2025-12-17"}
 
match response:
    case {"status": "error", "message": msg}:
        print(f"Error occurred: {msg}")
    case {"status": "success", "data": data}:
        print(f"Success! Data received: {data}")
    case _:
        print("Unknown response format")

Output:

Success! Data received: {'id': 123, 'name': 'Product'}

El patrón {"status": "success", "data": data} coincide aunque el diccionario tenga una clave adicional "timestamp". El patrón solo requiere que las claves especificadas existan con los valores especificados (o patrones).

13.3.6) Combinar literales y variables de enlace

Puedes mezclar patrones literales y variables de enlace para crear una lógica de coincidencia sofisticada: A diferencia de los ejemplos de tuplas anteriores que se centraban en coincidir estructura y posición, este ejemplo muestra cómo se pueden combinar valores literales y variables de enlace para implementar lógica de decisión del mundo real.

python
# Enrutador de solicitudes HTTP
request = ("GET", "/api/users", 42)
 
match request:
    case ("GET", "/", None):
        print("Homepage request")
    case ("GET", path, None):
        print(f"GET request for: {path}")
    case ("POST", path, data):
        print(f"POST request to {path} with data: {data}")
    case ("GET", path, user_id):
        print(f"GET request for {path} with user ID: {user_id}")
    case _:
        print("Unsupported request type")

Output:

GET request for /api/users with user ID: 42

Este ejemplo muestra cómo puedes coincidir con valores específicos (como "GET") mientras capturas otros (como path y user_id) en el mismo patrón.

13.3.7) Ejemplo práctico: Manejador de eventos

Construyamos un ejemplo completo que demuestre el poder de las variables de enlace:

python
# Manejador de eventos del juego
event = ("player_move", {"x": 10, "y": 5, "speed": 2})
 
match event:
    case ("player_move", {"x": x, "y": y}):
        print(f"Player moved to position ({x}, {y})")
    case ("player_attack", {"target": target, "damage": damage}):
        print(f"Player attacked {target} for {damage} damage")
    case ("item_pickup", {"item": item_name}):
        print(f"Player picked up: {item_name}")
    case ("game_over", {"score": final_score}):
        print(f"Game ended. Final score: {final_score}")
    case (event_type, data):
        print(f"Unknown event type: {event_type}")
        print(f"Event data: {data}")

Output:

Player moved to position (10, 5)

Este manejador de eventos coincide con tuplas que contienen un tipo de evento y un diccionario de datos del evento. Extrae valores específicos del diccionario según el tipo de evento, lo que hace que sea fácil procesar distintos tipos de eventos con código limpio y legible.

13.4) Añadir condiciones extra con la guarda if

13.4.1) ¿Qué son las guardas?

A veces necesitas que un patrón coincida y comprobar una condición adicional. Una guarda if(if guard) es una condición extra que puedes añadir a un patrón de caso usando la palabra clave if. El caso solo coincide si tanto el patrón coincide como la condición de la guarda es verdadera.

Esta es la sintaxis:

python
match subject:
    case pattern if condition:
        # El código se ejecuta solo si el patrón coincide Y condition es True

Veamos un ejemplo simple:

python
# Control de acceso por edad
age = 16
 
match age:
    case age if age >= 18:
        print("Adult - full access granted")
    case age if age >= 13:
        print("Teen - limited access granted")
    case age if age >= 0:
        print("Child - parental supervision required")
    case _:
        print("Invalid age")

Output:

Teen - limited access granted

En este ejemplo, la variable de enlace age captura el valor, y la guarda if age >= 13 añade una condición adicional. El caso coincide solo si el valor es 13 o mayor. Como age es 16, el segundo caso coincide y se ejecuta.

13.4.2) Cómo se evalúan las guardas

Entender el orden de evaluación es importante. Aquí tienes una visualización detallada que muestra cómo interactúan las guardas con el pattern matching:

No

No

No

Comprobar patrón del case

¿El patrón coincide?

Probar el siguiente case

Evaluar condición de la guarda

¿La guarda es True?

Ejecutar bloque del case

Salir de la sentencia match

¿Hay más cases?

No se encontró coincidencia: continuar después de match

Python primero comprueba si el patrón coincide. Solo si el patrón coincide, Python evalúa la condición de la guarda. Si la guarda es falsa, Python pasa al siguiente caso, aunque el patrón hubiera coincidido.

Aquí tienes un ejemplo que lo demuestra:

python
# Sistema de advertencia de temperatura
temperature = 25
 
match temperature:
    case temp if temp > 35:
        print(f"Extreme heat warning: {temp}°C")
    case temp if temp > 30:
        print(f"High temperature alert: {temp}°C")
    case temp if temp > 20:
        print(f"Comfortable temperature: {temp}°C")
    case temp if temp > 10:
        print(f"Cool temperature: {temp}°C")
    case temp:
        print(f"Cold temperature: {temp}°C")

Output:

Comfortable temperature: 25°C

Cada caso usa la variable de enlace temp para capturar el valor de temperatura, y luego aplica una guarda para comprobar si cae dentro de un rango específico. Los casos se comprueban en orden, así que se ejecuta el primer caso que coincide y tiene una guarda verdadera.

13.4.3) Guardas con patrones literales

Puedes combinar guardas con patrones literales para crear coincidencias más específicas:

python
# Calculadora de descuento basada en el tipo de artículo y la cantidad
item = ("book", 5)
 
match item:
    case ("book", quantity) if quantity >= 10:
        discount = 0.20  # 20% de descuento para 10+ libros
        print(f"Bulk book order: {quantity} books, {discount*100}% discount")
    case ("book", quantity) if quantity >= 5:
        discount = 0.10  # 10% de descuento para 5-9 libros
        print(f"Book order: {quantity} books, {discount*100}% discount")
    case ("book", quantity):
        discount = 0.0  # Sin descuento para menos de 5 libros
        print(f"Book order: {quantity} books, no discount")
    case (item_type, quantity):
        print(f"Order: {quantity} {item_type}(s)")

Output:

Book order: 5 books, 10.0% discount

El patrón ("book", quantity) coincide con una tupla donde el primer elemento es "book". La guarda if quantity >= 5 añade la condición de que la cantidad debe ser al menos 5.

13.4.4) Guardas con condiciones complejas

Las guardas pueden usar cualquier expresión booleana, incluyendo condiciones complejas con and, or y not:

python
# Evaluador de calificaciones de estudiante con consideración de asistencia
student = {"name": "Bob", "grade": 85, "attendance": 75}
 
match student:
    case {"grade": g, "attendance": a} if g >= 90 and a >= 90:
        status = "Excellent"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 80 and a >= 80:
        status = "Good"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 70 and a >= 70:
        status = "Satisfactory"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case {"grade": g, "attendance": a} if g >= 60 or a >= 60:
        status = "Needs Improvement"
        print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
    case _:
        print("Failing - immediate intervention required")

Output:

Grade: 85, Attendance: 75% - Status: Satisfactory

La guarda if g >= 70 and a >= 70 requiere que tanto la nota como la asistencia sean al menos 70. Como Bob tiene una nota de 85 y una asistencia del 75%, este caso coincide.

13.4.5) Ejemplo práctico: Sistema de autenticación de usuarios

Construyamos un ejemplo completo que use guardas para implementar un sistema de autenticación realista:

python
# Autenticación de usuario con acceso basado en roles
user = {"username": "alice", "role": "admin", "active": True, "login_attempts": 0}
 
match user:
    case {"active": False}:
        print("Account suspended - contact administrator")
    case {"login_attempts": attempts} if attempts >= 3:
        print("Account locked due to too many failed login attempts")
    case {"role": "admin", "active": True}:
        print("Admin access granted - full system privileges")
    case {"role": "moderator", "active": True}:
        print("Moderator access granted - content management privileges")
    case {"role": role, "active": True} if role in ["editor", "author"]:
        print(f"{role.capitalize()} access granted - content creation privileges")
    case {"role": "user", "active": True}:
        print("User access granted - basic privileges")
    case _:
        print("Access denied - invalid user profile")

Output:

Admin access granted - full system privileges

Este ejemplo demuestra cómo las guardas pueden implementar lógica de negocio compleja. El sistema comprueba múltiples condiciones: estado de la cuenta, intentos de inicio de sesión y permisos basados en roles. Cada caso maneja un escenario específico, haciendo que la lógica de autenticación sea clara y mantenible.

13.5) Coincidir con formas simples de secuencias y mapeos

13.5.1) Coincidir secuencias de longitud variable

A veces necesitas coincidir con secuencias de longitudes variables. El pattern matching de Python lo soporta con el operador *, que captura cero o más elementos.

python
# Analizador de comandos con argumentos variables
command = ["copy", "file1.txt", "file2.txt", "file3.txt", "backup/"]
 
match command:
    case ["help"]:
        print("Available commands: copy, move, delete")
    case ["copy", source, destination]:
        print(f"Copying {source} to {destination}")
    case ["copy", *sources, destination]:
        print(f"Copying {len(sources)} files to {destination}")
        print(f"Source files: {sources}")
    case ["delete", *files]:
        print(f"Deleting {len(files)} file(s): {files}")
    case _:
        print("Unknown command")

Output:

Copying 3 files to backup/
Source files: ['file1.txt', 'file2.txt', 'file3.txt']

El patrón ["copy", *sources, destination] coincide con una lista que empieza con "copy", termina con un destino y tiene cualquier número de archivos fuente en medio. *sources captura todos los elementos intermedios como una lista.

Importante: Solo puedes usar un patrón * por patrón de secuencia, y captura elementos como una lista:

python
# Analizador de entradas de log
log_entry = ["2025-12-17", "10:30:45", "ERROR", "Database", "connection", "timeout"]
 
match log_entry:
    case [date, time, "ERROR", *error_details]:
        print(f"Error on {date} at {time}")
        print(f"Error details: {' '.join(error_details)}")
    case [date, time, "WARNING", *warning_details]:
        print(f"Warning on {date} at {time}")
        print(f"Warning details: {' '.join(warning_details)}")
    case [date, time, level, *message]:
        print(f"{level} on {date} at {time}: {' '.join(message)}")

Output:

Error on 2025-12-17 at 10:30:45
Error details: Database connection timeout

13.5.2) Combinar patrones de secuencia con guardas

Puedes usar guardas con patrones de secuencia para añadir condiciones adicionales:

python
# Analizador de lista de notas
grades = [85, 92, 78, 95, 88]
 
match grades:
    case []:
        print("No grades recorded")
    case [grade] if grade >= 90:
        print(f"Single excellent grade: {grade}")
    case [grade] if grade < 60:
        print(f"Single failing grade: {grade}")
    case [*all_grades] if len(all_grades) >= 5 and sum(all_grades) / len(all_grades) >= 90:
        average = sum(all_grades) / len(all_grades)
        print(f"Excellent performance! Average: {average:.1f}")
    case [*all_grades] if len(all_grades) >= 5:
        average = sum(all_grades) / len(all_grades)
        print(f"Performance review: {len(all_grades)} grades, Average: {average:.1f}")
    case [*all_grades]:
        print(f"Insufficient data: only {len(all_grades)} grade(s)")

Output:

Performance review: 5 grades, Average: 87.6

El patrón [*all_grades] captura todos los elementos de la lista, y la guarda comprueba tanto la longitud como calcula el promedio para determinar el mensaje apropiado.


El pattern matching con match y case proporciona una forma potente y expresiva de manejar la toma de decisiones complejas en Python. Desde la coincidencia simple de valores hasta patrones estructurales sofisticados con guardas, esta característica te permite escribir código más limpio y mantenible para manejar múltiples casos y extraer datos de estructuras complejas.

A medida que sigas aprendiendo Python, verás que el pattern matching complementa la lógica condicional que aprendiste en el Capítulo 8, ofreciendo una alternativa elegante cuando lidias con múltiples casos distintos, especialmente al trabajar con datos estructurados. La clave es elegir la herramienta adecuada para cada situación: usa if-elif-else para condiciones simples y lógica booleana, y recurre a match-case cuando estés comprobando un valor contra múltiples posibilidades o trabajando con datos estructurados que necesitan extracción basada en patrones.

© 2025. Primesoft Co., Ltd.
support@primesoft.ai