Python & AI Tutorials Logo
Programação Python

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:

python
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 casar

Vamos começar com um exemplo simples que demonstra o conceito fundamental:

python
# 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 found

Neste 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:

python
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 found

Ambas as versões produzem o mesmo resultado. Porém, match-case oferece várias vantagens:

  1. Intenção mais clara: A instrução match mostra explicitamente que você está verificando um valor contra várias possibilidades
  2. Menos repetição: Você não repete o nome da variável em toda comparação
  3. Padrões mais poderosos: Como veremos, match-case pode fazer muito mais do que simples verificações de igualdade
  4. Melhor legibilidade: Para árvores de decisão complexas, match-case costuma 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:

python
# 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 complete

Como "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:

python
# 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 kitchen

Este 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:

python
# 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: 403

O 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:

python
# 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 events

Sem 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:

python
# 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 soon

Você pode usar padrões literais de tipos diferentes, e o match compara tanto o valor quanto o tipo:

python
# 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 enabled

Padrõ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":

python
# 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 |:

python
# 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 action

13.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:

python
# 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: 201

A 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:

python
# 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 detected

13.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:

python
# 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: save

O 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:

python
# 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 real

Output:

Some other status code

Agora com uma variável de ligação:

python
# 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 received

A 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.

python
# 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:

  1. O sujeito point é a tupla (3, 7)
  2. O Python verifica cada padrão case em ordem
  3. Os três primeiros padrões não casam porque exigem o valor 0 em uma posição específica, e a tupla (3, 7) não tem nenhum elemento igual a 0
  4. O padrão (x, y) casa porque é uma tupla de dois elementos
  5. O Python vincula x a 3 e y a 7
  6. O bloco case é executado com esses valores capturados

Aqui está outro exemplo mostrando diferentes padrões de tupla:

python
# 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 255

Essa 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:

python
# 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 steps

O 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:

python
# 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.98

O 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.

python
# 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 granted

O 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:

python
# 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.

python
# 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: 42

Este 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:

python
# 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:

python
match subject:
    case pattern if condition:
        # O código executa apenas se pattern casar E condition for True

Vamos ver um exemplo simples:

python
# 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 granted

Neste 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:

Não

Sim

Sim

Não

Sim

Não

Verificar o padrão case

O padrão casa?

Tentar o próximo case

Avaliar a condição da guarda

A guarda é True?

Executar o bloco case

Sair da instrução match

Mais cases?

Nenhum match encontrado - continuar após o match

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:

python
# 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°C

Cada 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:

python
# 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% discount

O 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:

python
# 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: Satisfactory

A 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:

python
# 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 privileges

Este 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.

python
# 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:

python
# 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 timeout

13.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:

python
# 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.6

O 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.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai