Decisões com condicionais
por Briar WestbrookEntenda o conceito
Até aqui os programas rodavam todas as linhas, de cima para baixo. Com o if, o programa passa a decidir: um bloco de código só é executado quando uma condição é verdadeira. Em Python, o bloco é marcado pela indentação (quatro espaços, por convenção) depois dos dois-pontos; não há chaves.
else cobre o caso contrário e elif (abreviação de "else if") testa novas condições em sequência. O Python avalia as condições de cima para baixo e executa só o primeiro bloco verdadeiro, por isso a ordem das condições importa.
As condições combinam comparações (==, !=, <, >=...) com os operadores lógicos and, or e not, e o Python aceita comparações encadeadas como 1 <= x <= 12. Valores como 0, "", None e listas vazias contam como falsos. Para escolher entre dois valores numa linha existe a expressão condicional (a if condição else b), e para comparar um valor com vários padrões, o match/case, disponível desde o Python 3.10.
if condição:seguido de um bloco indentado; o bloco só roda quando a condição éTrue.- Em
if/elif/else, só o primeiro bloco verdadeiro é executado: ordene as condições da mais específica para a mais geral. andexige as duas condições,oraceita qualquer uma enotinverte;1 <= x <= 12é uma comparação encadeada válida.0,0.0,"",Nonee coleções vazias são falsos numif; quase todo o resto é verdadeiro.valor = a if condição else bescolhe um valor numa linha;match/casecompara um valor com vários padrões, ecase _pega o resto.
Do conceito à prática
3 exemplos para ver a ideia funcionando.
01Devolução na biblioteca com if, elif e else
# emprestimo.py: if, elif e else decidem o que o programa faz.
dias_com_o_livro = 18
PRAZO = 14 # dias permitidos para cada empréstimo
# if: o bloco indentado só roda quando a condição é True.
if dias_com_o_livro > PRAZO:
print("Atenção: o prazo de devolução já passou.")
# if/else: exatamente um dos dois blocos roda.
atraso = dias_com_o_livro - PRAZO
if atraso > 0:
print(f"Atraso de {atraso} dias.")
else:
print("Devolução dentro do prazo.")
# if/elif/else: as condições são testadas de cima para baixo
# e só o primeiro bloco verdadeiro é executado.
if atraso <= 0:
situacao = "regular"
elif atraso <= 7:
situacao = "advertência"
elif atraso <= 30:
situacao = "multa"
else:
situacao = "suspensão"
print(f"Situação do leitor: {situacao}")
print("Fim da consulta.") # fora dos blocos: sempre roda
O exemplo mostra as três formas do if. O primeiro só imprime o aviso quando o prazo passou; o segundo, com else, sempre imprime uma de duas mensagens; o terceiro escolhe uma entre quatro situações com elif.
Na cadeia de elif, um atraso de 4 dias também é menor que 30, mas a situação fica advertência porque o Python para no primeiro teste verdadeiro. A última linha, sem indentação, está fora de qualquer bloco e roda sempre.
02Ingredientes da receita com and, or e not
# receita.py: and, or, not, comparação encadeada e valores "falsos".
porcoes = 6
tem_ovos = True
tem_leite = False
observacao = "" # texto vazio
# Comparação encadeada: equivale a 1 <= porcoes and porcoes <= 12.
if 1 <= porcoes <= 12:
print(f"{porcoes} porções: a receita cabe numa forma só.")
# and exige as duas condições; or aceita qualquer uma.
if tem_ovos and tem_leite:
print("Dá para fazer o bolo tradicional.")
elif tem_ovos or tem_leite:
print("Falta um ingrediente: use a versão adaptada.")
else:
print("Melhor escolher outra receita.")
# not inverte o valor lógico.
if not tem_leite:
print("Lista de compras: leite.")
# Texto vazio, 0, None e listas vazias contam como False num if.
if observacao:
print(f"Observação: {observacao}")
else:
print("Nenhuma observação para esta receita.")
# O operador in também gera um bool e combina bem com if.
ingrediente = "fermento"
if ingrediente in ("farinha", "açúcar", "fermento"):
print(f"{ingrediente.capitalize()} está na despensa.")
Aqui as condições ficam mais ricas. A comparação encadeada 1 <= porcoes <= 12 lê como na matemática, and e or combinam dois testes e not inverte um valor lógico. Como há ovos mas não há leite, o and é falso e o or é verdadeiro.
O if observacao: aproveita a regra de que texto vazio vale False, um atalho idiomático para perguntar "tem alguma coisa aqui?". Por fim, in testa se um valor está numa sequência e também devolve um bool.
03Comandos de um jogo com expressão condicional e match
# comandos.py: expressão condicional e match/case num jogo de texto.
def descrever_vida(vida):
# Expressão condicional: valor_se_verdadeiro if condição else valor_se_falso
estado = "em perigo" if vida < 30 else "bem"
return f"Vida {vida}: herói {estado}"
def executar(comando, chaves):
# match compara o valor com cada case, de cima para baixo.
match comando:
case "norte" | "sul" | "leste" | "oeste":
return f"Você caminha para o {comando}."
case "abrir" if chaves > 0: # guarda: o case só vale se o if for True
return "A porta range e se abre."
case "abrir":
return "A porta está trancada. Procure uma chave."
case "sair":
return "Até a próxima aventura!"
case _: # curinga: qualquer outro valor
return f"Comando desconhecido: {comando}"
def main():
print(descrever_vida(80))
print(descrever_vida(12))
print()
print(executar("norte", 0))
print(executar("abrir", 0))
print(executar("abrir", 1))
print(executar("dançar", 0))
print(executar("sair", 0))
if __name__ == "__main__":
main()
Em descrever_vida(), a expressão condicional escolhe o texto do estado numa linha só, sem um if de quatro linhas. Ela serve quando o objetivo é produzir um valor, não executar blocos diferentes.
Em executar(), o match compara o comando com cada case: | junta várias opções, a guarda if chaves > 0 só deixa o case valer quando há chave, e case _ pega qualquer comando desconhecido. Como o primeiro case "abrir" falha sem chave, o Python segue para o segundo.
Agora é com você
Tente resolver no rascunho antes de abrir a resposta. Os códigos não são executados nesta página.
01Faixas de frete da lojaFácil
Escreva a função mostrar_frete(total), que mostra o frete de uma compra: grátis a partir de R$ 200, R$ 9.90 a partir de R$ 100 e R$ 19.90 abaixo disso. Chame a função para as compras de 250, 120, 45.5 e 200 reais.
- A escolha da faixa usa uma única cadeia
if/elif/else. - Uma compra de exatamente R$ 200 tem frete grátis.
- O valor da compra aparece com duas casas decimais (
:.2f). - A saída tem exatamente 4 linhas, uma por chamada.
# frete.py: faixas de frete da loja com if/elif/else.
def mostrar_frete(total):
pass # troque pela cadeia de if/elif/else
mostrar_frete(250)
mostrar_frete(120)
mostrar_frete(45.5)
mostrar_frete(200)
Compra de R$ 250.00: frete grátis
Compra de R$ 120.00: frete de R$ 9.90
Compra de R$ 45.50: frete de R$ 19.90
Compra de R$ 200.00: frete grátis
Ver dica
Comece pela faixa mais alta: se o primeiro teste for total >= 100, a compra de 250 reais nunca chega ao frete grátis.
Ver resposta
# frete.py: faixas de frete da loja com if/elif/else.
def mostrar_frete(total):
# As faixas vão da maior para a menor: a primeira verdadeira vence.
if total >= 200:
print(f"Compra de R$ {total:.2f}: frete grátis")
elif total >= 100:
print(f"Compra de R$ {total:.2f}: frete de R$ 9.90")
else:
print(f"Compra de R$ {total:.2f}: frete de R$ 19.90")
mostrar_frete(250)
mostrar_frete(120)
mostrar_frete(45.5)
mostrar_frete(200)
Passo a passo
def mostrar_frete(total):define a função; o valor da compra chega pelo parâmetrototala cada chamada.if total >= 200:testa primeiro a faixa mais alta. O>=(e não>) garante que exatamente 200 reais também tenha frete grátis.elif total >= 100:só é avaliado quando o teste anterior falhou, então aqui já se sabe que a compra está abaixo de 200.else:não tem condição: cobre todas as compras que não entraram nas faixas anteriores, ou seja, abaixo de 100.- Nas f-strings,
{total:.2f}mostra o valor com duas casas, por isso45.5aparece como45.50e250como250.00. - As quatro chamadas no fim, sem indentação, ficam fora da função e são o que de fato executa o programa.
Por que funciona
Cada chamada passa por uma única cadeia if/elif/else, e o Python executa só o primeiro bloco cuja condição é verdadeira. Por isso as faixas podem ser escritas só com o limite de baixo: quem chega ao elif já não tem 200 reais ou mais.
O else garante que toda compra recebe exatamente uma mensagem, sem lacunas entre as faixas.
Erros comuns
- Testar
total >= 100antes detotal >= 200: a compra de 250 reais cai na primeira faixa verdadeira e recebe frete de 9.90. Ordene da faixa mais alta para a mais baixa. if total > 200:: a compra de exatamente 200 reais paga frete, contrariando a regra. Use>=.- Usar três
ifindependentes em vez deelif: a compra de 250 reais imprime duas linhas, porque também é>= 100. Encadeie comelif. - Esquecer os dois-pontos em
else: dáSyntaxError: expected ':'. Todoif,elifeelsetermina com:.
Outra forma de resolver
A função pode calcular só o valor do frete e deixar a impressão para o fim: frete = 0 if total >= 200 else 9.90 if total >= 100 else 19.90. Expressões condicionais aninhadas ficam difíceis de ler com mais de duas opções, então a cadeia de elif continua sendo a forma mais clara aqui.
Saída esperada
Compra de R$ 250.00: frete grátis
Compra de R$ 120.00: frete de R$ 9.90
Compra de R$ 45.50: frete de R$ 19.90
Compra de R$ 200.00: frete grátis
02Quem pode pegar livros emprestadosMédio
Escreva a função avaliar(nome, ativo, multa, livros) que libera um empréstimo só para leitores com cadastro ativo, sem multa e com menos de 3 livros em mãos. Quando recusar, a função mostra o primeiro motivo, na ordem: cadastro, multa, limite.
- A liberação usa uma única condição com
andreunindo as três regras. - O cadastro inativo é testado com
not ativo. - O limite de livros fica numa constante
LIMITE_LIVROS = 3usada na condição e na mensagem. - A multa aparece com duas casas decimais, e a leitora Júlia, que tem os três problemas, recebe só o motivo do cadastro.
# leitores.py: regras de empréstimo com and, not e elif.
LIMITE_LIVROS = 3
def avaliar(nome, ativo, multa, livros):
pass # libere ou mostre o motivo da recusa
avaliar("Helena", True, 0, 1)
avaliar("Otávio", False, 0, 0)
avaliar("Renata", True, 4.5, 2)
avaliar("Caio", True, 0, 3)
avaliar("Júlia", False, 2.0, 3)
Helena: empréstimo liberado
Otávio: recusado (cadastro inativo)
Renata: recusado (multa pendente de R$ 4.50)
Caio: recusado (limite de 3 livros atingido)
Júlia: recusado (cadastro inativo)
Ver dica
Teste primeiro o caso em que tudo está certo; nos elif seguintes, a ordem dos testes decide qual motivo aparece quando há mais de um problema.
Ver resposta
# leitores.py: regras de empréstimo com and, not e elif.
LIMITE_LIVROS = 3
def avaliar(nome, ativo, multa, livros):
# Uma única condição com and reúne as três regras.
if ativo and multa == 0 and livros < LIMITE_LIVROS:
print(f"{nome}: empréstimo liberado")
elif not ativo:
print(f"{nome}: recusado (cadastro inativo)")
elif multa > 0:
print(f"{nome}: recusado (multa pendente de R$ {multa:.2f})")
else:
print(f"{nome}: recusado (limite de {LIMITE_LIVROS} livros atingido)")
avaliar("Helena", True, 0, 1)
avaliar("Otávio", False, 0, 0)
avaliar("Renata", True, 4.5, 2)
avaliar("Caio", True, 0, 3)
avaliar("Júlia", False, 2.0, 3)
Passo a passo
LIMITE_LIVROS = 3fica no topo, em maiúsculas: a regra aparece num lugar só e é reaproveitada na condição e na mensagem.if ativo and multa == 0 and livros < LIMITE_LIVROS:só é verdadeira quando as três partes são verdadeiras; basta uma falhar para o empréstimo não ser liberado.elif not ativo:inverte obool: comativoigual aFalse,not ativoéTruee o motivo do cadastro é mostrado.elif multa > 0:só é avaliado para leitores ativos, porque os inativos já pararam no teste anterior.- O
elsefinal dispensa uma condição: se o cadastro está ativo e não há multa, o único motivo que sobra é o limite de livros. {multa:.2f}mostra4.5como4.50, no formato de dinheiro.- Júlia tem cadastro inativo, multa e 3 livros, mas só o primeiro
elifverdadeiro roda, por isso ela vê apenas o motivo do cadastro.
Por que funciona
O and resume as três regras numa pergunta só: "está tudo certo?". Quando a resposta é não, a cadeia de elif descobre o motivo testando os problemas na ordem de prioridade pedida, e a regra do primeiro bloco verdadeiro garante uma mensagem por leitor.
Como o and para no primeiro valor falso (avaliação em curto-circuito), o Python nem chega a olhar a multa de um leitor inativo nessa primeira condição.
Erros comuns
if ativo and multa == 0 or livros < 3:: oandé avaliado antes door, e Otávio, inativo e sem livros, seria liberado. Use sóandou ponha parênteses deixando a intenção explícita.elif ativo == False:: funciona, mas não é idiomático; linters como o Ruff apontam a comparação comFalse. Prefiranot ativo.- Trocar a ordem para testar a multa antes do cadastro: Júlia passaria a ver o motivo da multa, contrariando o enunciado. A ordem dos
elifé a ordem de prioridade. if ativo and not multa and livros < 3:commulta = 0.0: funciona porque0.0é falso, mas esconde a regra;multa == 0deixa claro o que está sendo testado.
Outra forma de resolver
Dá para testar os problemas primeiro e liberar no fim: if not ativo: ... elif multa > 0: ... elif livros >= LIMITE_LIVROS: ... else: print("liberado"). Essa forma evita a condição longa com and e é preferível quando há muitas regras; a versão com and deixa explícito, numa linha só, o que é preciso para ser liberado.
Saída esperada
Helena: empréstimo liberado
Otávio: recusado (cadastro inativo)
Renata: recusado (multa pendente de R$ 4.50)
Caio: recusado (limite de 3 livros atingido)
Júlia: recusado (cadastro inativo)
03Pontuação de uma rolagem de dadosDesafio
Escreva a função pontuar(d1, d2) para um jogo de dois dados: duplo seis vale 20 pontos, duplo um (olhos de cobra) vale 0, qualquer outra dupla vale a soma mais 5 e o resto vale a soma. A função devolve um texto com a paridade da soma, o nome da jogada, os pontos e se o jogador joga de novo (só com dados iguais e mais de 0 pontos).
- A jogada é escolhida com
match (d1, d2):, comcase (6, 6),case (1, 1), umcasecom guardaif a == becase _. - A paridade (
parouímpar) e ojoga de novo/passa a vezsão definidos com expressões condicionais. pontuar()devolve o texto comreturn; quem imprime é amain().main()só é chamada dentro deif __name__ == "__main__":.
# dados.py: pontuação de uma rolagem de dois dados com match/case.
def pontuar(d1, d2):
soma = d1 + d2
# use match (d1, d2) para escolher pontos e nome da jogada
return ""
def main():
print(pontuar(6, 6))
print(pontuar(1, 1))
print(pontuar(4, 4))
print(pontuar(2, 5))
print(pontuar(3, 6))
if __name__ == "__main__":
main()
6 e 6 (par): Duplo seis, 20 pontos, joga de novo
1 e 1 (par): Olhos de cobra, 0 pontos, passa a vez
4 e 4 (par): Dupla de 4, 13 pontos, joga de novo
2 e 5 (ímpar): Rolagem comum, 7 pontos, passa a vez
3 e 6 (ímpar): Rolagem comum, 9 pontos, passa a vez
Ver dica
Os padrões são testados de cima para baixo: os casos específicos (6 e 6, 1 e 1) precisam vir antes do case genérico de dupla, e o case _ sempre por último.
Ver resposta
# dados.py: pontuação de uma rolagem de dois dados com match/case.
def pontuar(d1, d2):
soma = d1 + d2
# match compara a tupla (d1, d2) com cada padrão, de cima para baixo.
match (d1, d2):
case (6, 6):
pontos, nome = 20, "Duplo seis"
case (1, 1):
pontos, nome = 0, "Olhos de cobra"
case (a, b) if a == b: # guarda: só vale para dados iguais
pontos, nome = soma + 5, f"Dupla de {a}"
case _:
pontos, nome = soma, "Rolagem comum"
# Expressões condicionais: um valor ou outro, numa linha só.
paridade = "par" if soma % 2 == 0 else "ímpar"
proximo = "joga de novo" if d1 == d2 and pontos > 0 else "passa a vez"
return f"{d1} e {d2} ({paridade}): {nome}, {pontos} pontos, {proximo}"
def main():
print(pontuar(6, 6))
print(pontuar(1, 1))
print(pontuar(4, 4))
print(pontuar(2, 5))
print(pontuar(3, 6))
if __name__ == "__main__":
main()
Passo a passo
soma = d1 + d2é calculada antes domatchporque aparece em várioscasee também na paridade.match (d1, d2):agrupa os dois dados numa tupla, e cadacasedescreve um formato possível dessa tupla.case (6, 6):ecase (1, 1):são padrões literais: só casam com esses valores exatos. Cada um atribui pontos e nome numa atribuição múltipla.case (a, b) if a == b:captura os dados nas variáveisaebe a guarda só aceita o padrão quando eles são iguais. Como os duplos seis e um já casaram antes, aqui só chegam as outras duplas.case _:é o curinga: qualquer rolagem que não casou com os padrões anteriores vale a soma simples.paridade = "par" if soma % 2 == 0 else "ímpar"escolhe um de dois textos numa linha, usando o resto da divisão por 2.proximo = "joga de novo" if d1 == d2 and pontos > 0 else "passa a vez"combina duas condições comand; olhos de cobra é dupla, mas tem 0 pontos e passa a vez.pontuar()devolve o texto comreturne amain()o imprime, o que separa o cálculo da exibição.
Por que funciona
O match deixa cada regra do jogo num case próprio, testado de cima para baixo como uma cadeia de elif, mas descrevendo o formato do valor em vez de escrever comparações. A guarda acrescenta uma condição extra a um padrão, e o curinga garante que toda rolagem tenha uma pontuação.
As expressões condicionais completam o texto sem blocos extras: quando a tarefa é escolher entre dois valores, elas são mais diretas que um if/else que só atribui uma variável.
Erros comuns
- Colocar
case (a, b) if a == b:antes decase (6, 6):: o duplo seis casa com o padrão genérico e vale 17 em vez de 20. Os padrões específicos vêm primeiro. case _:no início domatch: o Python acusaSyntaxError: wildcard makes remaining patterns unreachable. O curinga é sempre o último.case (d1, d1):para detectar dupla: dáSyntaxError: multiple assignments to name 'd1' in pattern, porque um padrão não pode capturar o mesmo nome duas vezes. Capture(a, b)e compare na guarda.proximo = "joga de novo" if d1 == d2 else "passa a vez": olhos de cobra ganharia outra jogada. Incluaand pontos > 0na condição.
Outra forma de resolver
Antes do Python 3.10, a mesma lógica era escrita com if d1 == 6 and d2 == 6: ... elif d1 == 1 and d2 == 1: ... elif d1 == d2: ... else: .... Essa forma ainda é a melhor quando as condições são faixas ou cálculos; o match brilha quando você compara o formato de um valor (tuplas, textos fixos, várias opções com |), como nas jogadas de dados.
Saída esperada
6 e 6 (par): Duplo seis, 20 pontos, joga de novo
1 e 1 (par): Olhos de cobra, 0 pontos, passa a vez
4 e 4 (par): Dupla de 4, 13 pontos, joga de novo
2 e 5 (ímpar): Rolagem comum, 7 pontos, passa a vez
3 e 6 (ímpar): Rolagem comum, 9 pontos, passa a vez