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:
- A condição não precisa de parênteses (embora sejam permitidos)
- 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
- Estruturas de controle — documentação oficial — https://docs.python.org/3/tutorial/controlflow.html
- Expressões condicionais (PEP 308) — https://peps.python.org/pep-0308/
- Truthy e Falsy em Python — https://docs.python.org/3/library/stdtypes.html#truth-value-testing
- MATTHES, Eric. Python Crash Course. 3. ed. No Starch Press, 2023. Cap. 5.
- LUTZ, Mark. Learning Python. 5. ed. O'Reilly Media, 2013. Cap. 12.
- HUNT, John. A Beginners Guide to Python 3 Programming. Springer, 2019. Cap. 7.
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.