Capítulo 02: Estruturas de Decisão: Condicionais Compostas e Pattern Matching (match-case)
Especialização em Sistemas com Python & POO com Type Hints • Capítulo 02
🗺️ Mapa Conceitual do Tópico
flowchart TD
subgraph DECISAO["Paradigmas de Decisão em Python 3.12+"]
COND["Condicionais Clássicas\n• if-elif-else com Encadeamento Relacional\n• Curto-Circuito Lógico (and / or / not)\n• Operador Ternário Condicional"]
SPM["Structural Pattern Matching (PEP 634/635/636)\n• Desestruturação de Sequências, Dicionários e Objetos\n• Cláusulas de Guarda e Validação Dinâmica\n• Subpadrões AS, OR (|) e Curinga (_)"]
end
subgraph PATTERNS["Catálogo de Padrões do match-case"]
LIT["Literal & Value Patterns\ncase 200: / case Status.ATIVO:"]
SEQ["Sequence Patterns com Splat\ncase [first, *middle, last]:"]
MAP["Mapping Patterns (Subconjuntos)\ncase {'tipo': 'PIX', 'valor': Decimal(v)}:"]
CLS["Class Patterns (__match_args__)\ncase Pedido(id=i, itens=[...]):"]
end
DECISAO --> PATTERNS
PATTERNS --> PROD["Aplicações Corporativas de Alta Criticidade\nGateways de Pagamento · Roteamento de Mensageria · Compiladores"]
style DECISAO fill:#ede7f6,stroke:#512da8,stroke-width:2px
style PATTERNS fill:#e1f5fe,stroke:#0288d1,stroke-width:2px
style PROD fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
🔀 1. Condicionais Clássicas e Semântica de Avaliação
Em Python, as estruturas condicionais operam sobre o conceito de Truth Value Testing (Valores da Verdade). Todo objeto possui um valor booleano intrínseco avaliado pelo método especial __bool__() ou __len__():
- Falsy por definição:
None,False, zeros de qualquer tipo numérico (0,0.0,Decimal('0')), sequências e coleções vazias ('',(),[],{},set(),range(0)). - Truthy: Todos os demais objetos em memória.
Curto-Circuito (Short-Circuit Evaluation)
Os operadores lógicos and e or não retornam necessariamente um booleano True ou False, mas sim o último operando avaliado:
a and b: Avaliaa. Seafor Falsy, retornaaimediatamente sem avaliarb. Se for Truthy, avalia e retornab.a or b: Avaliaa. Seafor Truthy, retornaaimediatamente sem avaliarb. Se for Falsy, avalia e retornab.
# Idioma de fallback seguro em microsserviços:
timeout_config: int = int(os.getenv("HTTP_TIMEOUT") or 30)
# Expressão Ternária Condicional (PEP 308):
status_label: str = "APROVADO" if score >= 700 else "REPROVADO"
# Comparações Encadeadas (Chained Comparisons):
# Em C/Java: (idade >= 18 && idade <= 65)
if 18 <= idade_colaborador <= 65:
processar_admissao(idade_colaborador)
🎯 2. Structural Pattern Matching (PEP 634, 635 e 636)
Introduzido formalmente no Python 3.10 e otimizado no Python 3.12+, o Structural Pattern Matching (match-case) não é uma simples variação do switch-case de linguagens procedurais. Trata-se de uma ferramenta declarativa de extração estrutural de dados combinada com validação tipada.
Taxonomia Completa de Padrões do match-case
| Tipo de Padrão | Sintaxe Formal | Semântica de Casamento e Extração |
|---|---|---|
| Literal Pattern | case 200: / case "JSON": |
Compara valores literais primitivos por igualdade estrita (==). |
| Value Pattern | case HttpStatus.NOT_FOUND: |
Compara contra constantes ou membros de enumerações com ponto. |
| Capture Pattern | case str(nome): / case valor: |
Vincula o valor desestruturado a uma nova variável local no escopo. |
| Wildcard Pattern | case _: |
Casamento universal que consome qualquer entrada (equivalente ao default). |
| OR Pattern | case 400 | 422 | 500: |
Casa se qualquer um dos subpadrões for satisfeito (\|). |
| AS Pattern | case [int(), int()] as coordenadas: |
Realiza o casamento e vincula a estrutura inteira a um alias (as). |
| Sequence Pattern | case [head, *tail]: |
Casa sequências (listas, tuplas) permitindo desestruturação com operador splat (*). |
| Mapping Pattern | case {"event": str(e), "user_id": int(u)}: |
Casa dicionários; verifica se as chaves existem, ignorando chaves adicionais não declaradas. |
| Class Pattern | case Transacao(id=i, valor=v): |
Casa instâncias de classes e valida atributos nominais ou posicionais. |
🛡️ 3. Cláusulas de Guarda (Guards) e Desestruturação Avançada
Uma Cláusula de Guarda é uma expressão condicional introduzida pela palavra-chave if após a especificação do padrão. O caso só é executado se o padrão estrutural casar E a expressão da guarda for verdadeira:
from decimal import Decimal
from typing import Any
def rotear_pagamento(evento: dict[str, Any]) -> str:
match evento:
# Mapping Pattern com captura e guarda de alta precisão
case {"canal": "PIX", "valor": Decimal(v)} if v > Decimal("50000.00"):
return f"Encaminhar para mesa de risco antifraude: R$ {v:,.2f}"
case {"canal": "PIX", "valor": Decimal(v), "chave": str(k)}:
return f"Liquidação instantânea PIX para {k}: R$ {v:,.2f}"
# Sequence Pattern com desestruturação de múltiplos lotes
case {"canal": "TED", "lotes": [primeiro, *outros]} if len(outros) >= 5:
return f"Processamento em lote corporativo prioritário ({len(outros) + 1} remessas)"
case _:
return "Protocolo de transação financeira desconhecido ou malformado"
🏛️ 4. Class Patterns e a Mágica de __match_args__
Para permitir a desestruturação posicional de instâncias de classes em blocos case, as classes podem definir a tupla estática __match_args__. Em dataclasses (PEP 557), ela é gerada automaticamente pelo compilador:
from dataclasses import dataclass
from decimal import Decimal
@dataclass(slots=True)
class PontoGeografico:
latitude: float
longitude: float
@dataclass(slots=True)
class PedidoEntrega:
codigo: str
origem: PontoGeografico
destino: PontoGeografico
valor_frete: Decimal
def auditar_rota(pedido: PedidoEntrega) -> str:
match pedido:
# Desestruturação aninhada com Class Pattern posicional e nominal
case PedidoEntrega(
codigo=cod,
origem=PontoGeografico(-23.5505, -46.6333), # Posição exata de SP
destino=PontoGeografico(lat, lon),
valor_frete=frete
) if frete > Decimal("100.00"):
return f"Entrega expressa originada em SP [Hub Central] para ({lat:.4f}, {lon:.4f}) com frete premium."
case PedidoEntrega(codigo=cod):
return f"Rota padrão interestadual para pedido {cod}."
📊 5. Matriz Comparativa: if-elif-else vs Dicionário de Despacho vs match-case
| Critério de Engenharia | Cadeia if-elif-else |
Despacho por Dicionário (Dispatch Table) | Structural Pattern Matching (match-case) |
|---|---|---|---|
| Complexidade Algorítmica | Linear $O(N)$ no pior caso. | Constante $O(1)$ por chave hash. | $O(N)$ de padrões, porém otimizado internamente na PVM. |
| Desestruturação de Dados | Manual e prolixa (obj[0], dict.get()). |
Inexistente (apenas roteia funções por chave). | Nativa e declarativa (extrai e valida simultaneamente). |
| Clareza em Regras Múltiplas | Degrada rapidamente com aninhamentos. | Boa para comandos simples, fraca para regras com guardas. | Excelente: Legibilidade limpa para regras complexas de domínio. |
| Sobrecarga de Manutenção | Alta probabilidade de bugs de limite (<=). |
Mínima para adição de novos comandos $1:1$. | Baixa; tipos e formatos são autoexplicativos. |