13. Fazendo Escolhas com match e case (Structural Pattern Matching)
Quando o seu programa precisa tomar decisões com base em vários valores ou padrões possíveis, você já aprendeu a usar cadeias if-elif-else no Capítulo 8. O Python 3.10 introduziu uma alternativa poderosa chamada correspondência estrutural de padrões (structural pattern matching) usando as instruções match e case. Esse recurso oferece uma forma mais limpa e expressiva de lidar com cenários complexos de tomada de decisão.
O pattern matching vai além de comparações simples de valores. Ele permite casar com a estrutura e o formato dos dados, extrair valores de objetos complexos e expressar decisões com múltiplos caminhos de forma mais legível. Embora cadeias if-elif-else funcionem perfeitamente bem em muitas situações, as instruções match-case brilham quando você está lidando com vários casos distintos, especialmente ao trabalhar com dados estruturados.
13.1) Apresentando as instruções match e case (Com base no if-elif do Capítulo 8)
13.1.1) A Estrutura Básica de match-case
Uma instrução match examina um valor (chamado de sujeito (subject)) e o compara com um ou mais padrões (patterns) definidos em cláusulas case. Quando um padrão casa, o Python executa o bloco de código associado àquele case.
Aqui está a estrutura básica:
match subject:
case pattern1:
# Código para executar se pattern1 casar
case pattern2:
# Código para executar se pattern2 casar
case pattern3:
# Código para executar se pattern3 casarVamos começar com um exemplo simples que demonstra o conceito fundamental:
# Manipulador simples de código de status HTTP
status_code = 404
match status_code:
case 200:
print("Success: Request completed")
case 404:
print("Error: Page not found")
case 500:
print("Error: Server error")Output:
Error: Page not foundNeste exemplo, a instrução match examina status_code (o sujeito). O Python verifica cada padrão case em ordem. Quando encontra que status_code é igual a 404, ele executa o bloco de código correspondente e então sai da instrução match. Os cases restantes não são verificados.
13.1.2) Como match-case Difere de if-elif-else
Você pode se perguntar: "Eu não poderia escrever isso com if-elif-else?" Sim, poderia:
status_code = 404
if status_code == 200:
print("Success: Request completed")
elif status_code == 404:
print("Error: Page not found")
elif status_code == 500:
print("Error: Server error")Output:
Error: Page not foundAmbas as versões produzem o mesmo resultado. Porém, match-case oferece várias vantagens:
- Intenção mais clara: A instrução
matchmostra explicitamente que você está verificando um valor contra várias possibilidades - Menos repetição: Você não repete o nome da variável em toda comparação
- Padrões mais poderosos: Como veremos,
match-casepode fazer muito mais do que simples verificações de igualdade - Melhor legibilidade: Para árvores de decisão complexas,
match-casecostuma ser mais fácil de entender
13.1.3) Quando Nenhum Padrão Casa
O que acontece se nenhum dos padrões casar? A instrução match simplesmente termina sem executar nenhum bloco case:
# Verificador de função do usuário
user_role = "guest"
match user_role:
case "admin":
print("Full system access granted")
case "moderator":
print("Content management access granted")
case "editor":
print("Editing access granted")
print("Role check complete")Output:
Role check completeComo "guest" não casa com nenhum dos padrões, nenhum bloco case é executado. O programa continua com o código após a instrução match. Esse comportamento é importante de entender — diferente de cadeias if-elif-else, em que você pode adicionar uma cláusula else final para capturar todos os outros casos, uma instrução match básica sem um padrão pega-tudo vai silenciosamente não fazer nada se nenhum padrão casar.
13.1.4) Exemplo Prático: Sistema de Seleção de Menu
Vamos construir um exemplo mais completo que demonstra a clareza de match-case para lidar com escolhas do usuário:
# Sistema de pedidos de restaurante
menu_choice = 3
match menu_choice:
case 1:
item = "Caesar Salad"
price = 8.99
print(f"You ordered: {item} - ${price}")
case 2:
item = "Grilled Chicken"
price = 14.99
print(f"You ordered: {item} - ${price}")
case 3:
item = "Vegetable Pasta"
price = 12.99
print(f"You ordered: {item} - ${price}")
case 4:
item = "Chocolate Cake"
price = 6.99
print(f"You ordered: {item} - ${price}")
print("Order submitted to kitchen")Output:
You ordered: Vegetable Pasta - $12.99
Order submitted to kitchenEste exemplo mostra como cada case pode conter várias instruções. Quando menu_choice casa com 3, o Python executa todas as três linhas naquele bloco case: atribuindo item, atribuindo price e imprimindo a confirmação do pedido.
13.2) Usando o curinga _, Padrões Literais e Múltiplos Padrões
13.2.1) O Padrão Curinga: Capturando Todo o Resto
O sublinhado _ é um padrão especial que casa com qualquer coisa. Normalmente ele é usado como o último case para lidar com todos os valores que não casaram com padrões anteriores — semelhante a uma cláusula else final em uma cadeia if-elif-else:
# Manipulador de código de status HTTP com case padrão
status_code = 403
match status_code:
case 200:
print("Success: Request completed")
case 404:
print("Error: Page not found")
case 500:
print("Error: Server error")
case _:
print(f"Unhandled status code: {status_code}")Output:
Unhandled status code: 403O padrão _ atua como um pega-tudo. Como 403 não casa com nenhum dos cases específicos, o padrão curinga casa e executa seu bloco. O padrão curinga vai casar com qualquer valor, então ele deve sempre ser colocado por último — quaisquer cases depois dele nunca seriam executados.
Aqui está por que o curinga é útil na prática:
# Agendador por dia da semana
day = "Saturday"
match day:
case "Monday":
print("Team meeting at 9 AM")
case "Wednesday":
print("Project review at 2 PM")
case "Friday":
print("Weekly report due")
case _:
print(f"{day}: No scheduled events")Output:
Saturday: No scheduled eventsSem o padrão curinga, se day fosse "Saturday", "Sunday" ou qualquer outro valor, a instrução match terminaria silenciosamente sem saída. O curinga garante que você lide com casos inesperados ou não especificados de forma elegante.
13.2.2) Padrões Literais: Casando Valores Específicos
Padrões literais (literal patterns) casam valores exatos. Nós já estamos usando eles — números, strings e valores booleanos são todos padrões literais:
# Controlador de semáforo
light_color = "yellow"
match light_color:
case "green":
print("Go")
case "yellow":
print("Caution: Light changing soon")
case "red":
print("Stop")
case _:
print("Invalid light color")Output:
Caution: Light changing soonVocê pode usar padrões literais de tipos diferentes, e o match compara tanto o valor quanto o tipo:
# Validador de configuração (usando tipos literais diferentes)
setting_value = True
match setting_value:
case True: # literal booleano
print("Feature enabled")
case False: # literal booleano
print("Feature disabled")
case None: # literal None
print("Feature not configured")
case 0: # literal inteiro
print("Feature explicitly turned off")
case "auto": # literal string
print("Feature set to automatic mode")
case _:
print("Invalid configuration value")Output:
Feature enabledPadrões literais funcionam com inteiros, floats, strings, booleanos e None. O Python verifica igualdade usando as mesmas regras do operador ==.
13.2.3) Múltiplos Padrões com o Operador OR
Às vezes você quer executar o mesmo código para vários valores diferentes. Você pode combinar vários padrões usando o operador | (pipe), que significa "ou":
# Detector de fim de semana
day = "Saturday"
match day:
case "Monday" | "Tuesday" | "Wednesday" | "Thursday" | "Friday":
print("It's a weekday - time to work!")
case "Saturday" | "Sunday":
print("It's the weekend - time to relax!")
case _:
print("Invalid day name")Output:
It's the weekend - time to relax!O operador | permite especificar vários padrões que devem disparar a mesma ação. Se o sujeito casar com qualquer um dos padrões separados por |, aquele case é executado. Isso é bem mais limpo do que escrever cases separados com blocos de código idênticos.
Você pode misturar diferentes tipos de padrões com |:
# Validador de entrada para perguntas de sim/não
response = "yes"
match response:
case True | "yes":
print("You confirmed the action")
case False | "no":
print("You cancelled the action")
case _:
print("Please answer yes or no")Output:
You confirmed the action13.2.4) Capturando Qual Alternativa Casou com as
Ao usar vários padrões com |, você pode querer saber qual valor específico casou. Você pode usar a palavra-chave as para capturar o valor casado:
# Manipulador de código de status com respostas agrupadas
status = 201
match status:
case 200 | 201 | 202 | 204 as success_code:
print(f"Success: {success_code}")
case 400 | 401 | 403 | 404 as client_error:
print(f"Client error: {client_error}")
case 500 | 502 | 503 as server_error:
print(f"Server error: {server_error}")
case _:
print("Unknown status code")Output:
Success: 201A palavra-chave as cria uma variável de ligação que captura qual alternativa casou. Neste exemplo, success_code fica vinculada a 201 porque esse foi o valor específico que casou entre as alternativas 200 | 201 | 202 | 204.
Aqui está outro exemplo mostrando como isso é útil para logging:
# Processador de nível de log
log_level = "WARN"
match log_level:
case "DEBUG" | "TRACE" as level:
print(f"Verbose logging: {level}")
print("Detailed diagnostic information will be recorded")
case "INFO" | "NOTICE" as level:
print(f"Informational: {level}")
print("Normal operation messages will be recorded")
case "WARN" | "WARNING" as level:
print(f"Warning level: {level}")
print("Potential issues detected")
case "ERROR" | "FATAL" | "CRITICAL" as level:
print(f"Error level: {level}")
print("Immediate attention required")
case _:
print("Unknown log level")Output:
Warning level: WARN
Potential issues detected13.3) Extraindo Valores com Variáveis de Ligação
13.3.1) O Que São Variáveis de Ligação?
Até aqui, casamos com valores literais. Mas o pattern matching se torna realmente poderoso quando você pode capturar ou extrair partes dos dados com os quais você está fazendo o match. Uma variável de ligação (binding variable) (também chamada de padrão de captura (capture pattern)) é um nome em um padrão que captura o valor casado e o disponibiliza no bloco case.
Aqui está um exemplo simples:
# Captura simples de valor
command = "save"
match command:
case "quit":
print("Exiting program")
case action: # Esta é uma variável de ligação
print(f"Executing action: {action}")Output:
Executing action: saveO padrão action é uma variável de ligação. Ele casa com qualquer valor (como o curinga _), mas, diferente de _, ele captura esse valor e o atribui ao nome action. Dentro do bloco case, você pode usar action para se referir ao valor casado.
Distinção importante: Uma variável de ligação casa com qualquer coisa, assim como _. A diferença é que _ descarta o valor, enquanto uma variável de ligação o captura para uso no bloco case.
13.3.2) Variáveis de Ligação vs Curingas
Vamos comparar variáveis de ligação e curingas diretamente:
# Usando curinga - o valor não é capturado
status = 403
match status:
case 200:
print("Success")
case _:
print("Some other status code") # Não dá para acessar o valor realOutput:
Some other status codeAgora com uma variável de ligação:
# Usando variável de ligação - o valor é capturado
status = 403
match status:
case 200:
print("Success")
case code: # Variável de ligação captura o valor
print(f"Status code {code} received")Output:
Status code 403 receivedA variável de ligação code captura o valor 403, deixando-o disponível dentro do bloco case. Isso é útil quando você precisa trabalhar com o valor real que não casou com seus padrões específicos.
13.3.3) Casando Padrões de Tupla e Extraindo Componentes
O pattern matching fica especialmente poderoso com dados estruturados como tuplas. Você pode casar com o formato de uma tupla e extrair seus componentes ao mesmo tempo. Embora estudemos tuplas em detalhe no Capítulo 15, este exemplo foca apenas em como padrões de tupla funcionam em instruções match.
# Sistema de coordenadas - casando um padrão de tupla
point = (3, 7)
match point:
case (0, 0):
print("Origin point")
case (0, y): # Casa qualquer ponto no eixo y
print(f"On y-axis at y={y}")
case (x, 0): # Casa qualquer ponto no eixo x
print(f"On x-axis at x={x}")
case (x, y): # Casa qualquer outro ponto
print(f"Point at coordinates ({x}, {y})")Output:
Point at coordinates (3, 7)Vamos detalhar o que está acontecendo:
- O sujeito
pointé a tupla(3, 7) - O Python verifica cada padrão case em ordem
- Os três primeiros padrões não casam porque exigem o valor
0em uma posição específica, e a tupla(3, 7)não tem nenhum elemento igual a0 - O padrão
(x, y)casa porque é uma tupla de dois elementos - O Python vincula
xa3eya7 - O bloco case é executado com esses valores capturados
Aqui está outro exemplo mostrando diferentes padrões de tupla:
# Analisador de cores RGB
color = (255, 0, 0)
match color:
case (0, 0, 0):
print("Black")
case (255, 255, 255):
print("White")
case (r, 0, 0): # Vermelho puro com intensidade variável
print(f"Pure red with intensity {r}")
case (0, g, 0): # Verde puro
print(f"Pure green with intensity {g}")
case (0, 0, b): # Azul puro
print(f"Pure blue with intensity {b}")
case (r, g, b): # Qualquer outra cor
print(f"RGB color: red={r}, green={g}, blue={b}")Output:
Pure red with intensity 255Essa entrada casa com o padrão (r, 0, 0) porque a tupla tem três elementos, os dois últimos são 0, e o primeiro valor fica vinculado a r.
13.3.4) Casando Padrões de Lista
Você também pode casar padrões de lista e extrair elementos. Vamos cobrir listas em detalhe no Capítulo 14; por enquanto, este exemplo foca em como padrões de lista funcionam em instruções match:
# Comando com argumentos
command = ["move", "north", "5"]
match command:
case ["quit"]:
print("Exiting game")
case ["look"]:
print("You look around the room")
case ["move", direction]:
print(f"Moving {direction}")
case ["move", direction, distance]:
print(f"Moving {direction} for {distance} steps")
case _:
print("Unknown command")Output:
Moving north for 5 stepsO padrão ["move", direction, distance] casa com uma lista de três elementos em que o primeiro elemento é "move". Ele captura o segundo elemento como direction e o terceiro como distance.
Aqui está um exemplo prático com comprimentos de lista variáveis:
# Processador de itens do carrinho de compras
item = ["laptop", 999.99, 2]
match item:
case [name]: # Item apenas com nome
print(f"Item: {name} (no price or quantity specified)")
case [name, price]: # Item com nome e preço
print(f"Item: {name}, Price: ${price}, Quantity: 1 (default)")
case [name, price, quantity]: # Informações completas do item
total = price * quantity
print(f"Item: {name}, Price: ${price}, Quantity: {quantity}")
print(f"Subtotal: ${total}")
case _:
print("Invalid item format")Output:
Item: laptop, Price: $999.99, Quantity: 2
Subtotal: $1999.98O case [name, price, quantity] é executado porque a lista tem exatamente três elementos, e cada elemento fica vinculado à sua variável correspondente.
13.3.5) Casando Padrões de Dicionário
O pattern matching funciona com dicionários também, permitindo casar chaves específicas e extrair seus valores. Embora estudemos dicionários em detalhe no Capítulo 16, esta seção foca apenas em como padrões de dicionário funcionam em instruções match.
# Processador de perfil de usuário
user = {"name": "Alice", "role": "admin", "active": True}
match user:
case {"role": "admin", "active": True}:
print("Active administrator - full access granted")
case {"role": "admin", "active": False}:
print("Inactive administrator - access suspended")
case {"role": role, "active": True}: # Captura o valor de role
print(f"Active user with role: {role}")
case {"role": role, "active": False}:
print(f"Inactive user with role: {role}")
case _:
print("Invalid user profile")Output:
Active administrator - full access grantedO case {"role": "admin", "active": True} é executado porque padrões de dicionário exigem casar pares chave–valor, e essa correspondência exata é verificada antes de padrões mais gerais.
Padrões de dicionário são flexíveis — eles casam se as chaves especificadas existirem com os valores especificados, mesmo que o dicionário tenha chaves adicionais:
# Manipulador de resposta de API
response = {"status": "success", "data": {"id": 123, "name": "Product"}, "timestamp": "2025-12-17"}
match response:
case {"status": "error", "message": msg}:
print(f"Error occurred: {msg}")
case {"status": "success", "data": data}:
print(f"Success! Data received: {data}")
case _:
print("Unknown response format")Output:
Success! Data received: {'id': 123, 'name': 'Product'}O padrão {"status": "success", "data": data} casa mesmo que o dicionário tenha uma chave adicional "timestamp". O padrão só exige que as chaves especificadas existam com os valores especificados (ou padrões).
13.3.6) Combinando Literais e Variáveis de Ligação
Você pode misturar padrões literais e variáveis de ligação para criar uma lógica de match sofisticada: Diferente dos exemplos anteriores de tupla que focavam em casar estrutura e posição, este exemplo mostra como valores literais e variáveis de ligação podem ser combinados para implementar uma lógica de decisão do mundo real.
# Roteador de requisições HTTP
request = ("GET", "/api/users", 42)
match request:
case ("GET", "/", None):
print("Homepage request")
case ("GET", path, None):
print(f"GET request for: {path}")
case ("POST", path, data):
print(f"POST request to {path} with data: {data}")
case ("GET", path, user_id):
print(f"GET request for {path} with user ID: {user_id}")
case _:
print("Unsupported request type")Output:
GET request for /api/users with user ID: 42Este exemplo mostra como você pode casar valores específicos (como "GET") enquanto captura outros (como path e user_id) no mesmo padrão.
13.3.7) Exemplo Prático: Manipulador de Eventos
Vamos construir um exemplo completo que demonstra o poder das variáveis de ligação:
# Manipulador de eventos do jogo
event = ("player_move", {"x": 10, "y": 5, "speed": 2})
match event:
case ("player_move", {"x": x, "y": y}):
print(f"Player moved to position ({x}, {y})")
case ("player_attack", {"target": target, "damage": damage}):
print(f"Player attacked {target} for {damage} damage")
case ("item_pickup", {"item": item_name}):
print(f"Player picked up: {item_name}")
case ("game_over", {"score": final_score}):
print(f"Game ended. Final score: {final_score}")
case (event_type, data):
print(f"Unknown event type: {event_type}")
print(f"Event data: {data}")Output:
Player moved to position (10, 5)Este manipulador de eventos casa tuplas que contêm um tipo de evento e um dicionário de dados do evento. Ele extrai valores específicos do dicionário com base no tipo do evento, facilitando processar diferentes tipos de eventos com código limpo e legível.
13.4) Adicionando Condições Extras com a Guarda if
13.4.1) O Que São Guardas?
Às vezes você precisa casar um padrão e verificar uma condição adicional. Uma guarda if (if guard) é uma condição extra que você pode adicionar a um padrão case usando a palavra-chave if. O case só casa se tanto o padrão casar quanto a condição de guarda for verdadeira.
Aqui está a sintaxe:
match subject:
case pattern if condition:
# O código executa apenas se pattern casar E condition for TrueVamos ver um exemplo simples:
# Controle de acesso baseado em idade
age = 16
match age:
case age if age >= 18:
print("Adult - full access granted")
case age if age >= 13:
print("Teen - limited access granted")
case age if age >= 0:
print("Child - parental supervision required")
case _:
print("Invalid age")Output:
Teen - limited access grantedNeste exemplo, a variável de ligação age captura o valor, e a guarda if age >= 13 adiciona uma condição extra. O case só casa se o valor for 13 ou maior. Como age é 16, o segundo case casa e executa.
13.4.2) Como Guardas São Avaliadas
Entender a ordem de avaliação é importante. Aqui vai uma visualização detalhada mostrando como guardas interagem com pattern matching:
O Python primeiro verifica se o padrão casa. Somente se o padrão casar é que o Python avalia a condição de guarda. Se a guarda for falsa, o Python passa para o próximo case — mesmo que o padrão tenha casado.
Aqui está um exemplo que demonstra isso:
# Sistema de avisos de temperatura
temperature = 25
match temperature:
case temp if temp > 35:
print(f"Extreme heat warning: {temp}°C")
case temp if temp > 30:
print(f"High temperature alert: {temp}°C")
case temp if temp > 20:
print(f"Comfortable temperature: {temp}°C")
case temp if temp > 10:
print(f"Cool temperature: {temp}°C")
case temp:
print(f"Cold temperature: {temp}°C")Output:
Comfortable temperature: 25°CCada case usa a variável de ligação temp para capturar o valor da temperatura e então aplica uma guarda para verificar se ela cai dentro de uma faixa específica. Os cases são verificados em ordem, então o primeiro case que casar com uma guarda verdadeira executa.
13.4.3) Guardas com Padrões Literais
Você pode combinar guardas com padrões literais para criar matches mais específicos:
# Calculadora de desconto baseada no tipo de item e na quantidade
item = ("book", 5)
match item:
case ("book", quantity) if quantity >= 10:
discount = 0.20 # 20% de desconto para 10+ livros
print(f"Bulk book order: {quantity} books, {discount*100}% discount")
case ("book", quantity) if quantity >= 5:
discount = 0.10 # 10% de desconto para 5-9 livros
print(f"Book order: {quantity} books, {discount*100}% discount")
case ("book", quantity):
discount = 0.0 # Sem desconto para menos de 5 livros
print(f"Book order: {quantity} books, no discount")
case (item_type, quantity):
print(f"Order: {quantity} {item_type}(s)")Output:
Book order: 5 books, 10.0% discountO padrão ("book", quantity) casa uma tupla em que o primeiro elemento é "book". A guarda if quantity >= 5 adiciona a condição de que a quantidade deve ser pelo menos 5.
13.4.4) Guardas com Condições Complexas
Guardas podem usar qualquer expressão booleana, incluindo condições complexas com and, or e not:
# Avaliador de notas do aluno considerando presença
student = {"name": "Bob", "grade": 85, "attendance": 75}
match student:
case {"grade": g, "attendance": a} if g >= 90 and a >= 90:
status = "Excellent"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case {"grade": g, "attendance": a} if g >= 80 and a >= 80:
status = "Good"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case {"grade": g, "attendance": a} if g >= 70 and a >= 70:
status = "Satisfactory"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case {"grade": g, "attendance": a} if g >= 60 or a >= 60:
status = "Needs Improvement"
print(f"Grade: {g}, Attendance: {a}% - Status: {status}")
case _:
print("Failing - immediate intervention required")Output:
Grade: 85, Attendance: 75% - Status: SatisfactoryA guarda if g >= 70 and a >= 70 exige que tanto a nota quanto a presença sejam pelo menos 70. Como Bob tem nota 85 e presença de 75%, esse case casa.
13.4.5) Exemplo Prático: Sistema de Autenticação de Usuário
Vamos construir um exemplo completo que usa guardas para implementar um sistema de autenticação realista:
# Autenticação de usuário com acesso baseado em função
user = {"username": "alice", "role": "admin", "active": True, "login_attempts": 0}
match user:
case {"active": False}:
print("Account suspended - contact administrator")
case {"login_attempts": attempts} if attempts >= 3:
print("Account locked due to too many failed login attempts")
case {"role": "admin", "active": True}:
print("Admin access granted - full system privileges")
case {"role": "moderator", "active": True}:
print("Moderator access granted - content management privileges")
case {"role": role, "active": True} if role in ["editor", "author"]:
print(f"{role.capitalize()} access granted - content creation privileges")
case {"role": "user", "active": True}:
print("User access granted - basic privileges")
case _:
print("Access denied - invalid user profile")Output:
Admin access granted - full system privilegesEste exemplo demonstra como guardas podem implementar lógica de negócio complexa. O sistema verifica várias condições: status da conta, tentativas de login e permissões baseadas em função. Cada case trata um cenário específico, deixando a lógica de autenticação clara e fácil de manter.
13.5) Fazendo Match em Formatos Simples de Sequência e Mapeamento
13.5.1) Fazendo Match em Sequências de Comprimento Variável
Às vezes você precisa casar sequências de comprimentos variados. O pattern matching do Python suporta isso com o operador *, que captura zero ou mais elementos.
# Parser de comandos com argumentos variáveis
command = ["copy", "file1.txt", "file2.txt", "file3.txt", "backup/"]
match command:
case ["help"]:
print("Available commands: copy, move, delete")
case ["copy", source, destination]:
print(f"Copying {source} to {destination}")
case ["copy", *sources, destination]:
print(f"Copying {len(sources)} files to {destination}")
print(f"Source files: {sources}")
case ["delete", *files]:
print(f"Deleting {len(files)} file(s): {files}")
case _:
print("Unknown command")Output:
Copying 3 files to backup/
Source files: ['file1.txt', 'file2.txt', 'file3.txt']O padrão ["copy", *sources, destination] casa uma lista que começa com "copy", termina com um destino e tem qualquer número de arquivos de origem no meio. O *sources captura todos os elementos do meio como uma lista.
Importante: Você só pode usar um padrão * por padrão de sequência, e ele captura elementos como uma lista:
# Parser de entradas de log
log_entry = ["2025-12-17", "10:30:45", "ERROR", "Database", "connection", "timeout"]
match log_entry:
case [date, time, "ERROR", *error_details]:
print(f"Error on {date} at {time}")
print(f"Error details: {' '.join(error_details)}")
case [date, time, "WARNING", *warning_details]:
print(f"Warning on {date} at {time}")
print(f"Warning details: {' '.join(warning_details)}")
case [date, time, level, *message]:
print(f"{level} on {date} at {time}: {' '.join(message)}")Output:
Error on 2025-12-17 at 10:30:45
Error details: Database connection timeout13.5.2) Combinando Padrões de Sequência com Guardas
Você pode usar guardas com padrões de sequência para adicionar condições extras:
# Analisador de lista de notas
grades = [85, 92, 78, 95, 88]
match grades:
case []:
print("No grades recorded")
case [grade] if grade >= 90:
print(f"Single excellent grade: {grade}")
case [grade] if grade < 60:
print(f"Single failing grade: {grade}")
case [*all_grades] if len(all_grades) >= 5 and sum(all_grades) / len(all_grades) >= 90:
average = sum(all_grades) / len(all_grades)
print(f"Excellent performance! Average: {average:.1f}")
case [*all_grades] if len(all_grades) >= 5:
average = sum(all_grades) / len(all_grades)
print(f"Performance review: {len(all_grades)} grades, Average: {average:.1f}")
case [*all_grades]:
print(f"Insufficient data: only {len(all_grades)} grade(s)")Output:
Performance review: 5 grades, Average: 87.6O padrão [*all_grades] captura todos os elementos na lista, e a guarda verifica tanto o comprimento quanto calcula a média para determinar a mensagem apropriada.
O pattern matching com match e case fornece uma forma poderosa e expressiva de lidar com tomada de decisão complexa em Python. De match simples de valores a padrões estruturais sofisticados com guardas, esse recurso permite escrever código mais limpo e mais fácil de manter para lidar com vários casos e extrair dados de estruturas complexas.
À medida que você continua aprendendo Python, você vai perceber que o pattern matching complementa a lógica condicional que você aprendeu no Capítulo 8, oferecendo uma alternativa elegante ao lidar com vários casos distintos, especialmente ao trabalhar com dados estruturados. A chave é escolher a ferramenta certa para cada situação: use if-elif-else para condições simples e lógica booleana, e use match-case quando você estiver verificando um valor contra várias possibilidades ou trabalhando com dados estruturados que precisam de extração baseada em padrões.