🎯 Correspondência de Padrões em Python

Em poucas palavras

Definição técnica ou simplificada do conceito.


📝 Notas e Desenvolvimento


🔗 Conexões e Contexto


📚 Referências e Fontes

Citações Diretas

📂 Outros Conteúdos Preservados

Sintaxe Básica

A correspondência de padrões utiliza a declaração match seguida por uma série de blocos case.

match <expressao>:
    case <padrao_1>:
        # Código a ser executado se a expressão corresponder ao padrao_1
    case <padrao_2>:
        # Código a ser executado se a expressão corresponder ao padrao_2
    case _: # Padrão curinga (wildcard)
        # Código a ser executado se a expressão não corresponder a nenhum dos padrões anteriores
  • <expressao>: O valor que está sendo comparado.
  • <padrao>: A estrutura ou valor com o qual a expressão é comparada.
  • _: O padrão curinga, que corresponde a qualquer coisa e é útil para capturar casos padrão ou ignorar partes de um padrão.

Tipos de Padrões

A correspondência de padrões é muito flexível e pode lidar com vários tipos de padrões:

  1. Padrões Literais: Correspondem a valores exatos.

    status_code = 200
    match status_code:
        case 200:
            print("OK")
        case 404:
            print("Não encontrado")
        case _:
            print("Outro status")
    # Saída: OK
  2. Padrões de Sequência: Desestruturam listas, tuplas e outras sequências.

    ponto = (10, 20)
    match ponto:
        case (x, y):
            print(f"Ponto em x={x}, y={y}")
        case _:
            print("Não é um ponto 2D")
    # Saída: Ponto em x=10, y=20

    Isso é uma extensão poderosa do Desempacotar sequencias em Python.

  3. Padrões de Mapeamento: Desestruturam dicionários.

    usuario = {'nome': 'Alice', 'idade': 30}
    match usuario:
        case {'nome': n, 'idade': i}:
            print(f"Nome: {n}, Idade: {i}")
        case _:
            print("Formato de usuário desconhecido")
    # Saída: Nome: Alice, Idade: 30
  4. Padrões de Classe: Correspondem a instâncias de classes e seus atributos.

    class Ponto:
        def __init__(self, x, y):
            self.x = x
            self.y = y
     
    p = Ponto(5, 10)
    match p:
        case Ponto(x=val_x, y=val_y):
            print(f"Objeto Ponto com x={val_x}, y={val_y}")
        case _:
            print("Não é um objeto Ponto")
    # Saída: Objeto Ponto com x=5, y=10
  5. Padrões de Captura: Atribuem o valor correspondente a uma variável.

    valor = "hello"
    match valor:
        case msg: # 'msg' captura o valor de 'valor'
            print(f"Capturado: {msg}")
    # Saída: Capturado: hello
  6. Padrões as: Capturam um subpadrão.

    coordenada = (1, 2, 3)
    match coordenada:
        case (x, y, z) as ponto_3d:
            print(f"Ponto 3D: {ponto_3d}, x={x}, y={y}, z={z}")
    # Saída: Ponto 3D: (1, 2, 3), x=1, y=2, z=3
  7. Padrões OR: Combinam múltiplos padrões com |.

    dia = "Sábado"
    match dia:
        case "Sábado" | "Domingo":
            print("É fim de semana!")
        case _:
            print("É dia de semana.")
    # Saída: É fim de semana!
  8. Guards (if): Adicionam condições adicionais aos padrões.

    idade = 18
    match idade:
        case i if i < 18:
            print("Menor de idade")
        case i if i >= 18:
            print("Maior de idade")
    # Saída: Maior de idade

Exemplos Práticos

Exemplo 1: Processamento de Comandos Simples

def processar_comando(comando):
    match comando.split():
        case ["get", obj]:
            print(f"Pegando o {obj}.")
        case ["swing", obj]:
            print(f"Balançando o {obj}! AHHHH!")
        case ["abrir", "porta", direcao] if direcao in ["norte", "sul", "leste", "oeste"]:
            print(f"Abrindo a porta para o {direcao}.")
        case _: # Curinga para qualquer outro caso de correspondência
            raise ValueError(f"Não sei como '{comando}'")
 
processar_comando("swing espada")
 
### Saída: Balançando o espada! AHHHH!
 
processar_comando("get chave")
 
### Saída: Pegando o chave.
 
processar_comando("abrir porta norte")
 
### Saída: Abrindo a porta para o norte.
 
 
 
### processar_comando("correr rápido")
 
 
 
### Levantaria ValueError: Não sei como 'correr rápido'
 

Exemplo 2: Desestruturação de Dados Complexos com Condições

Este exemplo demonstra como desestruturar dados aninhados e aplicar condições (if) para filtrar resultados, similar ao que se faria com Desempacotar sequencias em Python e lógica condicional, mas de forma mais integrada.

metro_areas = [
    ('Tokyo', 'JP', 36.933, (35.689722, 139.691667)),
    ('Delhi NCR', 'IN', 21.935, (28.613889, 77.208889)),
    ('Mexico City', 'MX', 20.142, (19.433333, -99.133333)),
    ('New York-Newark', 'US', 20.104, (40.808611, -74.020386)),
    ('São Paulo', 'BR', 19.649, (-23.547778, -46.635833)),
]
 
print(f'{"Cidade":15} | {"Latitude":>9} | {"Longitude":>9}')
print("-" * 40)
 
for record in metro_areas:
    match record:
        # Padrão de sequência: [nome, _, _, (lat, lon)]
        # O '_' ignora os elementos 'código do país' e 'população'.
        # O padrão aninhado '(lat, lon)' desestrutura a tupla de coordenadas.
        # A guarda 'if lon <= 0' filtra apenas as cidades no hemisfério ocidental.
        case [name, _, _, (lat, lon)] if lon <= 0:
            print(f'{name:15} | {lat:9.4f} | {lon:9.4f}')
        case _:
            # Este caso pode ser usado para lidar com outros formatos de registro
            # ou para ignorar registros que não correspondem ao critério.
            pass
 
### Saída:
 
 
 
### Cidade          |  Latitude | Longitude
 
 
 
### ----------------------------------------
 
 
 
### Mexico City     |   19.4333 |  -99.1333
 
 
 
### New York-Newark |   40.8086 |  -74.0204
 
 
 
### São Paulo       |  -23.5478 |  -46.6358
 

A correspondência de padrões em Python é uma ferramenta poderosa para escrever código mais limpo e expressivo, especialmente ao lidar com estruturas de dados complexas ou múltiplas condições.

:: Referência :: PEP 634 – Structural Pattern Matching: Specification