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: Avalia a. Se a for Falsy, retorna a imediatamente sem avaliar b. Se for Truthy, avalia e retorna b.
  • a or b: Avalia a. Se a for Truthy, retorna a imediatamente sem avaliar b. Se for Falsy, avalia e retorna b.
# 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.