Estruturas de Controle: if, elif e else

Estruturas de Controle: if, elif e else

Decidir é o que separa um script de um programa. O if, o elif e o else, a indentação que substitui as chaves, e a regra de veracidade que faz zero, string vazia e lista vazia valerem como falso — com a armadilha que isso arma quando zero é um valor legítimo. Mais o ternário e o match, chegado na versão 3.10.
Python

• • 13 min de leitura

Um programa que executa sempre as mesmas instruções na mesma ordem tem utilidade limitada. A capacidade de tomar decisões — executar um bloco de código ou outro dependendo de uma condição — é o que torna os programas verdadeiramente úteis. Em Python, isso é feito com as estruturas if, elif e else.

A Estrutura if

A forma mais simples de controle de fluxo:

temperatura = 38.5

if temperatura > 37.5:
    print("Febre detectada.")
    print("Consulte um médico.")

Dois detalhes importantes da sintaxe Python:

  1. A condição não precisa de parênteses (embora sejam permitidos)
  2. O bloco de código é delimitado por indentação — convencionalmente 4 espaços. Não há chaves {} como em C, Java ou JavaScript

Se a condição for False, o bloco é ignorado e a execução continua após ele.

if e else

Para executar um bloco alternativo quando a condição é falsa:

idade = 16

if idade >= 18:
    print("Acesso permitido.")
else:
    print("Acesso negado. Você é menor de idade.")

if, elif e else

Quando há mais de duas possibilidades, use elif (contração de "else if"):

nota = 75

if nota >= 90:
    print("Conceito A")
elif nota >= 80:
    print("Conceito B")
elif nota >= 70:
    print("Conceito C")
elif nota >= 60:
    print("Conceito D")
else:
    print("Reprovado")

A partir do Python 3.10 existe uma alternativa para o caso em que o encadeamento compara sempre a mesma coisa: a instrução match. Ela não substitui o elif — o exemplo das notas, que testa faixas, continua sendo trabalho de elif — mas é mais clara quando se compara um valor contra alternativas fixas.

comando = "sair"

match comando:
    case "listar":
        print("mostrando itens")
    case "sair" | "fechar":      # o | aceita mais de uma alternativa
        print("encerrando")
    case _:                      # o _ faz o papel do else
        print("comando desconhecido")

Ao contrário do switch de C e de Java, o match do Python não é só comparação de igualdade: ele casa formato, e consegue desmontar listas e dicionários direto no case. Por ora basta saber que existe e que exige 3.10 ou mais — em versão anterior, o programa nem chega a rodar.

Python avalia as condições de cima para baixo e executa apenas o primeiro bloco cuja condição seja verdadeira. Os demais são ignorados.

Condições Compostas

É comum combinar múltiplas condições em um único if:

salario = 5000
tempo_empresa = 3

if salario > 3000 and tempo_empresa >= 2:
    print("Elegível para promoção.")

# Verificando faixas
valor = 150

if 100 <= valor <= 200:
    print("Valor dentro da faixa esperada.")

A notação 100 <= valor <= 200 é um encadeamento de comparações exclusivo do Python, visto em Operadores e Expressões — muito mais legível do que valor >= 100 and valor <= 200.

Valores Truthy e Falsy

Em Python, qualquer valor pode ser avaliado em um contexto booleano. Alguns valores são considerados "falsos" por natureza:

# Valores Falsy — avaliados como False
False
None
0
0.0
""        # string vazia
[]        # lista vazia
{}        # dicionário vazio
()        # tupla vazia
set()     # conjunto vazio

Decorar a lista, no entanto, é a pior forma de aprender isso, porque ela não para aí: a regra geral é que um objeto é falso quando está vazio ou vale zero, e qualquer tipo pode decidir isso por conta própria. Um objeto que você mesmo escrever será falso se definir __len__ devolvendo 0, ou __bool__ devolvendo False — é assim que um carrinho de compras vazio pode ser testado com um simples if carrinho:. Vale reparar também no que não está na lista: a string "0", a string "False" e a lista [0] são todas verdadeiras, porque não estão vazias — o conteúdo não é olhado.

Tudo o que não estiver nessa lista é considerado True (Truthy). Isso permite escrever condições mais expressivas:

nome = input("Digite seu nome: ")

if nome:
    print(f"Olá, {nome}!")
else:
    print("Nenhum nome foi digitado.")

lista_de_tarefas = []

if lista_de_tarefas:
    print("Você tem tarefas pendentes.")
else:
    print("Nenhuma tarefa pendente.")

O Operador Ternário

Python permite escrever um if/else simples em uma única linha — chamado de expressão condicional ou operador ternário:

idade = 20
status = "maior de idade" if idade >= 18 else "menor de idade"
print(status)  # maior de idade

A sintaxe é: valor_se_verdadeiro if condição else valor_se_falso

Use com moderação — é elegante para casos simples, mas pode prejudicar a legibilidade em condições complexas.

if com in

Uma combinação muito comum em Python é usar in dentro de condições:

linguagens = ["Python", "JavaScript", "Go", "Rust"]

escolha = "Python"

if escolha in linguagens:
    print(f"{escolha} está na lista.")

# Verificando caracteres em strings
email = "usuario@exemplo.com"

if "@" in email and "." in email:
    print("Formato de e-mail válido.")
else:
    print("E-mail inválido.")

Aninhamento de if

É possível colocar um if dentro de outro — chamado de if aninhado:

tem_conta = True
saldo = 1500
valor_saque = 500

if tem_conta:
    if saldo >= valor_saque:
        saldo -= valor_saque
        print(f"Saque realizado. Saldo restante: R$ {saldo}")
    else:
        print("Saldo insuficiente.")
else:
    print("Você não possui conta cadastrada.")

Aninhamento excessivo dificulta a leitura. Uma boa prática é usar cláusulas de guarda — retornando ou encerrando cedo quando uma condição não é atendida:

def realizar_saque(tem_conta, saldo, valor):
    if not tem_conta:
        print("Sem conta cadastrada.")
        return

    if saldo < valor:
        print("Saldo insuficiente.")
        return

    saldo -= valor
    print(f"Saque realizado. Saldo: R$ {saldo}")

Exemplo Completo: Classificador de IMC

peso = float(input("Digite seu peso (kg): "))
altura = float(input("Digite sua altura (m): "))

imc = peso / altura ** 2

print(f"\nSeu IMC é: {imc:.2f}")

if imc < 18.5:
    print("Classificação: Abaixo do peso")
elif imc < 25.0:
    print("Classificação: Peso normal")
elif imc < 30.0:
    print("Classificação: Sobrepeso")
elif imc < 35.0:
    print("Classificação: Obesidade grau I")
elif imc < 40.0:
    print("Classificação: Obesidade grau II")
else:
    print("Classificação: Obesidade grau III")

Duas ideias desta parte vão reaparecer em todo código Python que você escrever. A primeira é que a indentação não é convenção de estilo: é sintaxe, e o interpretador se recusa a rodar quando ela não fecha. Isso incomoda quem vem de linguagens com chaves e, passada a estranheza, elimina de uma vez uma classe inteira de discussão sobre formatação — não existe o bloco que parece pertencer a um lugar e pertence a outro.

A segunda é a regra de veracidade, e ela merece mais cuidado do que parece. Escrever if lista: em vez de if len(lista) > 0: é idiomático e legível, e funciona porque vazio é falso. O problema aparece quando o valor testado é um número ou pode ser nulo: aí 0 e None respondem igual, embora signifiquem coisas opostas — um é uma resposta, o outro é a ausência dela. A regra prática que evita o defeito é escolher o teste pelo que se quer perguntar: if lista: quando a pergunta é sobre estar vazio, if valor is not None: quando a pergunta é sobre existir.

Fontes e leituras recomendadas

Exercícios

Exercício 1

Uma função registra a leitura de um sensor e grava no banco só quando há leitura. O código é if leitura:. Os testes passam, e em campo o sistema perde dados de forma intermitente e sem erro nenhum no log. O que está errado?

Ver resposta

✓ Resposta: A leitura de valor zero está sendo descartada como se o sensor não tivesse respondido. O if leitura: não pergunta "veio alguma coisa?" — pergunta "isso é verdadeiro?", e em Python são falsos o 0, o 0.0, a string vazia, a lista vazia e o None. Os cinco caem no mesmo balde, mas só o None significa ausência. Um sensor de temperatura marcando zero grau, um contador zerado, um saldo zerado: todos legítimos, todos silenciosamente jogados fora. É intermitente porque depende do valor lido, e não aparece no log porque nada falhou — o programa fez exatamente o que foi escrito. O conserto é testar a pergunta real: if leitura is not None:. A regra que evita a classe inteira de defeito é simples de enunciar: use a veracidade quando a pergunta for mesmo sobre estar vazio — if lista:, if nome: — e use is not None quando a pergunta for sobre existir. Vale notar, para completar, que o inverso também engana: a string "0" é verdadeira, porque não está vazia, e ninguém olha o que tem dentro dela.

Exercício 2

Um colega troca o encadeamento de elif do classificador de notas por uma sequência de if independentes, argumentando que "dá na mesma e fica mais fácil de ler". Ele está certo?

Ver resposta

✓ Resposta: Não, e o resultado muda. O elif forma uma cadeia em que no máximo um bloco executa: assim que uma condição é verdadeira, as demais nem são avaliadas. Uma sequência de if independentes avalia todas, e todas as verdadeiras executam. No classificador de notas isso é fatal, porque as condições se sobrepõem de propósito: uma nota 95 satisfaz >= 90, >= 80, >= 70 e >= 60, e o aluno receberia quatro conceitos em vez de um. O encadeamento é o que permite escrever apenas o limite inferior de cada faixa — a superior está implícita no fato de as anteriores terem falhado. Sem ele, cada teste precisaria dos dois limites: if 80 <= nota < 90:. Há dois casos em que o colega teria razão. O primeiro é quando as condições são mutuamente exclusivas por construção e nunca se sobrepõem — aí o resultado coincide, embora o elif continue sendo mais rápido e mais honesto sobre a intenção. O segundo é quando se quer que mais de uma ação aconteça, por exemplo acumulando mensagens de validação de um formulário: aí os if separados são a estrutura certa, e usar elif é que seria o defeito, porque só o primeiro erro seria reportado.

Exercício 3

Você copia um trecho de código de um site e cola no seu arquivo. Ao rodar, o Python reclama de IndentationError ou TabError numa linha que, na tela, está visivelmente alinhada com as outras. Como isso é possível e como se resolve?

Ver resposta

✓ Resposta: Porque o que o editor mostra e o que está no arquivo são coisas diferentes. Um bloco indentado com tabulação e outro com espaços podem ocupar exatamente a mesma largura na tela — depende só de como o editor está configurado para exibir o tab — e ainda assim serem bytes distintos. O interpretador compara os caracteres, não o alinhamento visual, e recusa o arquivo. É o defeito clássico do copiar e colar, porque a página web quase sempre entrega espaços e o seu arquivo talvez use tab, ou o contrário. Em Python 3 misturar os dois é erro declarado, e não uma escolha de estilo: a mensagem TabError: inconsistent use of tabs and spaces in indentation existe só para esse caso. A solução definitiva não é contar espaços na mão — é configurar o editor para inserir espaços ao pressionar Tab e mostrar os caracteres invisíveis, que é o que a PEP 8 recomenda com seus quatro espaços por nível. Para consertar um arquivo já bagunçado, qualquer formatador resolve de uma vez. E vale a observação mais ampla: a indentação em Python é sintaxe, não convenção. Em C um bloco mal indentado é feio; em Python, é outro programa, ou nenhum.

Exercício 4

O artigo valida e-mail com if "@" in email and "." in email:. Que entradas passam nessa validação sem serem e-mails, e qual é a abordagem correta?

Ver resposta

✓ Resposta: Passam muitas. "@." passa. ".@" passa. "a@b" não passa, mas "a.b@" passa, assim como "@@@..." e qualquer frase que por acaso contenha os dois caracteres. O teste verifica presença, não posição nem estrutura — e nem sequer exige que o ponto venha depois do arroba. Mas o ponto mais importante é outro, e é contraintuitivo: tentar validar e-mail por regra própria é quase sempre a decisão errada, porque o formato real é muito mais permissivo do que a intuição sugere. Endereços com sinal de mais, com aspas, com caracteres acentuados no domínio e com domínios sem ponto (como localhost) são todos válidos, e as expressões regulares que circulam na internet rejeitam endereços legítimos de gente real. A abordagem correta tem duas camadas. Na entrada, uma verificação frouxa, só para pegar erro de digitação óbvio — há exatamente um arroba, há algo antes e algo depois dele. E, para saber se o endereço existe, o único teste que funciona é mandar um e-mail de confirmação com um link. Nenhuma regra sintática distingue joao@empresa.com de jaoo@empresa.com, e é esse o erro que importa pegar.

Exercício 5

O resumo do artigo recomenda "evitar aninhamento excessivo — prefira cláusulas de guarda". Explique o que é uma cláusula de guarda e por que ela deixa o código melhor, e não apenas mais curto.

Ver resposta

✓ Resposta: Cláusula de guarda é tratar os casos inválidos logo no início da função, saindo dela imediatamente, em vez de envolver o caso válido em if aninhados. Em vez de if conta_existe: contendo if conta_ativa: contendo if saldo_suficiente: contendo finalmente o saque, escreve-se o contrário: if not conta_existe: return, if not conta_ativa: return, if saldo < valor: return, e então o saque, sem indentação nenhuma. O ganho não é economia de linhas — é carga mental. Com aninhamento, quem lê a linha do saque precisa manter na cabeça três condições simultâneas para saber em que circunstância aquilo executa, e a indentação cresce até o código escapar pela margem. Com guardas, cada condição é lida, resolvida e descartada: ao chegar no saque, tudo o que restou é o caminho feliz, e ele está no nível zero. Há um segundo ganho, menos citado e mais valioso: as guardas põem cada erro ao lado da sua causa, o que torna natural dar uma mensagem específica para cada um — em vez do else solitário lá no fim, distante de tudo, que responde "operação inválida" sem dizer qual das três coisas falhou. E vale para além do if: é a mesma ideia por trás de tratar erro cedo em vez de embrulhar o programa inteiro num bloco de exceção gigante.

Comentários

Mais em Python

Projeto 3: Bot de Automação com Scraping e Notificações
Projeto 3: Bot de Automação com Scraping e Notificações

Um bot de vagas com coleta pela API do RemoteOK, filtro por pontuação, SQLite…

Design Patterns em Python
Design Patterns em Python

Singleton, Factory, Builder, Adapter, Facade, Strategy, Observer, Command…

Introdução ao Desenvolvimento Web com Flask
Introdução ao Desenvolvimento Web com Flask

Flask começa com uma rota e uma função, e os erros aparecem no que ele deixa…