A **correspondência de padrões estrutural** (Structural Pattern Matching), introduzida no [[Linguagem de programação Python|Python]] 3.10 (via PEP 634), é uma poderosa declaração `match` que permite avaliar uma expressão e compará-la com uma série de padrões. Ela simplifica a lógica condicional complexa e a desestruturação de dados, tornando o código mais legível e conciso. # Sintaxe Básica A correspondência de padrões utiliza a declaração `match` seguida por uma série de blocos `case`. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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. ```python 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 `|`. ```python 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. ```python 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** ```python 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. ```python 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](https://peps.python.org/pep-0634/)