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

Funções: definição, parâmetros e escopo
Funções: definição, parâmetros e escopo

Nomear um bloco de código é o primeiro passo para escrever programas que…

Dominando o Python
Dominando o Python

A série começa pelo terreno: o que Python é hoje, onde a linguagem de fato…

Algoritmos de Ordenação e Busca
Algoritmos de Ordenação e Busca

Os algoritmos clássicos de ordenação e busca, com o que cada um ensina a…