DMarlon Studio

Lección 12 · 12 de 20

Enumeraciones y match/case · Python

Estados de pedido con Enum y eventos procesados con match/case en Python: patrones de valores, diccionarios, secuencias, capturas y guardas.

Python · Enumeraciones y match/case en DMarlon Studio: el código del ejemplo y su salida en la terminal

Una enumeración (Enum) agrupa un conjunto cerrado de valores con nombre. Status.PAID es mucho más seguro que la cadena "paid": una errata como Status.PIAD falla en el acto. Cada miembro tiene name y value, se puede recorrer con for status in Status y se puede buscar por su valor con Status("paid"). El primer bucle escribe cada miembro con !s (que da Status.PAID) y su valor con !r.

`match` compara un valor con una serie de patrones y ejecuta el primer case que encaja. En next_step, case Status.PENDING: compara con un miembro concreto, y `case _:` recoge todo lo demás, como un else.

En handle los patrones describen la forma de los datos. {"type": "order", "id": oid, ...} encaja con cualquier diccionario que tenga esas claves (aunque tenga más) y captura los valores en oid y total. El if total >= 100 es una guarda: si no se cumple, se prueba el siguiente case, que es el que acepta el pedido 8.

("refund", oid, amount) encaja con cualquier secuencia de tres elementos que empiece por "refund" (tupla o lista; las cadenas no cuentan). ["cancel", *ids] admite cualquier longitud y guarda el resto en la lista ids.

El último evento, "ping", no encaja con nada y cae en case _. {event!r} lo escribe con repr(), entre comillas.

Código · main.py

from enum import Enumclass Status(Enum):    PENDING = "pending"    PAID = "paid"    SHIPPED = "shipped"def next_step(status):    match status:        case Status.PENDING:            return "wait for payment"        case Status.PAID:            return "pack and ship"        case _:                       # anything else            return "nothing to do"def handle(event):    match event:                      # match by shape and capture values        case {"type": "order", "id": oid, "total": total} if total >= 100:            return f"order {oid}: big order, check stock"        case {"type": "order", "id": oid}:            return f"order {oid}: accepted"        case ("refund", oid, amount):            return f"refund {amount} EUR for order {oid}"        case ["cancel", *ids]:            return f"cancel {len(ids)} orders: {ids}"        case _:            return f"unknown event: {event!r}"for status in Status:    print(f"{status!s:<15} {status.value!r:<10} -> {next_step(status)}")for event in [{"type": "order", "id": 7, "total": 250}, {"type": "order", "id": 8},              ("refund", 7, 40), ["cancel", 3, 4], "ping"]:    print(handle(event))

Salida · python3 main.py

Status.PENDING  'pending'  -> wait for payment
Status.PAID     'paid'     -> pack and ship
Status.SHIPPED  'shipped'  -> nothing to do
order 7: big order, check stock
order 8: accepted
refund 40 EUR for order 7
cancel 2 orders: [3, 4]
unknown event: 'ping'

Para recordar

  • Enum da nombres fijos a un conjunto cerrado de valores.
  • match prueba los case en orden y ejecuta el primero que encaja.
  • Los patrones pueden capturar valores en variables.
  • if después del patrón añade una condición (guarda).
  • case _: recoge todo lo que no ha encajado.

Ejercicio

Añada un estado CANCELLED a Status y un case en next_step que devuelva "refund the customer"; después, haga que los reembolsos con amount negativo escriban un aviso.