Python Condições Aninhadas
Algumas perguntas só fazem sentido depois de outra. No caixa eletrônico, só faz sentido perguntar o valor do saque se a senha estiver certa. Na porta do show, só faz sentido conferir a idade de quem tem ingresso. Para isso, você põe um if dentro do bloco de outro if. Isso se chama condição aninhada (como um ninho dentro do outro, ou uma caixa dentro de outra caixa).
- A escrever um
if(com ou semelse) dentro do bloco de outro. - Como os níveis de recuo (4, 8, 12 espaços) mostram o que está dentro de quê.
- A descobrir a qual
ifcadaelsepertence, pela coluna. - Quando o aninhamento pode virar um
andou uma escadaelif, e por que a "pirâmide" deifé difícil de ler. - Os erros reais: o
elseno nível errado (que não dá erro nenhum), oNameErrorde uma variável criada só num caminho e osIndentationError.
Todos os programas desta aula rodaram no Python 3.14 do computador fictício da Ana (usuária ana, computador notebook), na pasta pessoal dela, com python3 arquivo.py.
A ideia: a porta do show
Na entrada de um show, o segurança faz duas perguntas, uma depois da outra:
- "Você tem ingresso?" Se não: "Compre na bilheteria", e a conversa acaba aí.
- Se sim, aí vem a segunda pergunta: "Você tem 18 anos?" Se sim, pulseira verde (pode comprar bebida); se não, pulseira azul.
A pergunta da idade está dentro do "sim" da primeira. Quem não tem ingresso nunca ouve a segunda pergunta. Em Python:
ingresso = input("Tem ingresso? (sim/não) ")
if ingresso == "sim":
idade = int(input("Idade: "))
if idade >= 18:
print("Pulseira verde: pode comprar bebida.")
else:
print("Pulseira azul: sem bebida.")
print("Pode entrar. Bom show!")
else:
print("Compre o ingresso na bilheteria.")
$ python3 show.py Tem ingresso? (sim/não) sim Idade: 15 Pulseira azul: sem bebida. Pode entrar. Bom show! $ python3 show.py Tem ingresso? (sim/não) sim Idade: 20 Pulseira verde: pode comprar bebida. Pode entrar. Bom show! $ python3 show.py Tem ingresso? (sim/não) não Compre o ingresso na bilheteria. « nem perguntou a idade
- if ingresso == "sim":
- O
ifde fora (na margem, 0 espaços). - idade = int(input(…))
- 4 espaços: está dentro do bloco do
ifde fora. Só roda para quem respondeu "sim". - if idade >= 18:
- O
ifde dentro, também com 4 espaços: ele é uma das linhas do bloco de fora. - print("Pulseira verde…")
- 8 espaços: dentro do bloco do
ifde dentro. - else: (4 espaços)
- Na mesma coluna do
if idade >= 18: é o "senão" dele. - print("Pode entrar…")
- 4 espaços: voltou para o bloco de fora. Roda para todo mundo que tem ingresso, qualquer que seja a idade.
- else: (0 espaços)
- Na margem, na coluna do
if ingresso == "sim": é o "senão" doifde fora.
1. Os níveis de recuo
Cada if aninhado acrescenta mais 4 espaços. Dá para ler o programa como caixas dentro de caixas:
| Recuo | Onde a linha está | No show.py |
|---|---|---|
| 0 espaços | No programa principal: roda sempre | ingresso = input(…), if ingresso == "sim":, o último else: |
| 4 espaços | Dentro do primeiro if (ou do seu else) | idade = …, if idade >= 18:, print("Pode entrar…") |
| 8 espaços | Dentro do segundo if, que está dentro do primeiro | Os dois print das pulseiras |
Para saber a qual if um else pertence, olhe só a coluna em que ele começa e suba até encontrar um if que comece na mesma coluna. É esse. A maioria dos editores de código desenha linhas verticais finas no recuo justamente para ajudar nisso.
2. O caixa eletrônico
Um exemplo com else nos dois níveis. O saldo da Ana é R$ 200,00:
saldo = 200.0
senha = input("Senha: ")
if senha == "1234":
print("Senha correta.")
valor = float(input("Valor do saque: R$ "))
if valor <= saldo:
saldo = saldo - valor
print(f"Saque feito. Saldo: R$ {saldo:.2f}")
else:
print("Saldo insuficiente.")
else:
print("Senha errada.")
print("Obrigado por usar o caixa.")
$ python3 saque.py Senha: 1234 Senha correta. Valor do saque: R$ 50 Saque feito. Saldo: R$ 150.00 « senha certa e valor que cabe Obrigado por usar o caixa. $ python3 saque.py Senha: 1234 Senha correta. Valor do saque: R$ 500 Saldo insuficiente. « senha certa, valor alto: else de dentro Obrigado por usar o caixa. $ python3 saque.py Senha: 9999 Senha errada. « else de fora: nem perguntou o valor Obrigado por usar o caixa.
São três caminhos possíveis, e o programa faz no máximo duas perguntas. Desenhando como uma árvore:
| Senha certa? | Valor cabe no saldo? | Resultado |
|---|---|---|
| sim | sim | Saque feito |
| sim | não | Saldo insuficiente |
| não | (nem pergunta) | Senha errada |
Experimente: a entrada preparada é a senha 1234 e o valor 80. Rode e confira o saldo. Depois mude o saldo inicial para 50.0 e rode de novo: agora cai no "Saldo insuficiente". Por fim, troque a senha certa no código por outra e veja o terceiro caminho.
saldo = 200.0
senha = input("Senha: ")
if senha == "1234":
print("Senha correta.")
valor = float(input("Valor do saque: R$ "))
if valor <= saldo:
saldo = saldo - valor
print(f"Saque feito. Saldo: R$ {saldo:.2f}")
else:
print("Saldo insuficiente.")
else:
print("Senha errada.")
print("Obrigado por usar o caixa.")
3. Votar no Brasil: um if/else dentro de outro
As regras: abaixo de 16 anos, não pode votar. De 16 a 17 e a partir de 70, o voto é facultativo (opcional). De 18 a 69, é obrigatório.
idade = int(input("Idade: "))
if idade >= 16:
if idade >= 18 and idade < 70:
print("Voto obrigatório.")
else:
print("Voto facultativo.")
else:
print("Ainda não pode votar.")
$ python3 voto.py Idade: 15 Ainda não pode votar. $ python3 voto.py Idade: 17 Voto facultativo. $ python3 voto.py Idade: 30 Voto obrigatório. $ python3 voto.py Idade: 75 Voto facultativo.
O if de fora separa quem pode votar de quem não pode. Só para quem pode, o de dentro decide entre obrigatório e facultativo. (Uma escada elif também resolveria; veja Formas diferentes.)
Missão: o programa do show ainda dá a mesma pulseira para todo mundo. Dentro do bloco do if de fora, troque a linha marcada por um if/else aninhado: 18 anos ou mais, Pulseira verde: pode comprar bebida.; menos, Pulseira azul: sem bebida.. A entrada preparada é sim e depois 15.
ingresso = input("Tem ingresso? (sim/não) ")
if ingresso == "sim":
idade = int(input("Idade: "))
print("Pulseira verde: pode comprar bebida.") # troque esta linha
print("Pode entrar. Bom show!")
else:
print("Compre o ingresso na bilheteria.")
ingresso = input("Tem ingresso? (sim/não) ")
if ingresso == "sim":
idade = int(input("Idade: "))
if idade >= 18:
print("Pulseira verde: pode comprar bebida.")
else:
print("Pulseira azul: sem bebida.")
print("Pode entrar. Bom show!")
else:
print("Compre o ingresso na bilheteria.")
4. Quando o aninhamento pode virar and
A loja da Ana dá frete grátis para compras a partir de R$ 100 e só para Teresina. Dá para escrever aninhado:
total = 120.0
cidade = "Teresina"
if total >= 100:
if cidade == "Teresina":
print("Frete grátis!")
ou com and, numa condição só:
total = 120.0
cidade = "Teresina"
if total >= 100 and cidade == "Teresina":
print("Frete grátis!")
$ python3 frete_aninhado.py Frete grátis! $ python3 frete_and.py Frete grátis!
Os dois mostram o mesmo. Quando o if de fora não tem else e o bloco dele só tem o if de dentro, os dois juntos são o mesmo que um if com and, e a versão com and é mais curta e mais fácil de ler. Já quando cada nível tem a sua mensagem de "senão" (como no caixa eletrônico, que diz "Senha errada" ou "Saldo insuficiente"), o aninhamento é o jeito natural.
5. A pirâmide de if
Cada nível empurra o código 4 espaços para a direita. Com três ou quatro níveis, o programa vira uma pirâmide deitada, e fica difícil ver qual else responde a qual pergunta. A Ana fez a validação de um cadastro assim:
nome = "Ana"
idade = 15
cidade = "Teresina"
if nome != "":
if idade >= 18:
if cidade == "Teresina":
print("Cadastro aprovado!")
else:
print("Só atendemos Teresina.")
else:
print("Precisa ter 18 anos.")
else:
print("Falta o nome.")
Cada mensagem de erro ficou longe da pergunta que a causa: "Falta o nome." está na última linha, a 9 linhas do if nome != "". Invertendo as perguntas (perguntando pelo problema, e não pelo que está certo), a pirâmide vira uma escada elif, toda na mesma coluna:
nome = "Ana"
idade = 15
cidade = "Teresina"
if nome == "":
print("Falta o nome.")
elif idade < 18:
print("Precisa ter 18 anos.")
elif cidade != "Teresina":
print("Só atendemos Teresina.")
else:
print("Cadastro aprovado!")
$ python3 piramide.py Precisa ter 18 anos. $ python3 escada.py Precisa ter 18 anos.
Mesmo resultado, e agora cada problema está colado na sua mensagem. Uma boa regra prática: se passou de dois ou três níveis, procure um jeito de achatar (com and, com elif ou, mais adiante, separando partes em funções).
Formas diferentes de escrever a regra do voto
if idade >= 16:
if idade >= 18 and idade < 70:
print("Voto obrigatório.")
else:
print("Voto facultativo.")
else:
print("Ainda não pode votar.")
if idade < 16:
print("Ainda não pode votar.")
elif 18 <= idade < 70:
print("Voto obrigatório.")
else:
print("Voto facultativo.")
| Forma | Quando usar |
|---|---|
| Aninhada | Quando a segunda pergunta só faz sentido depois da primeira (a senha antes do valor, o ingresso antes da idade), e principalmente quando a segunda precisa de algo que só a primeira obtém (o input() do valor) |
Escada elif | Quando são faixas ou casos de um mesmo valor. Costuma ficar mais curta e toda na mesma coluna |
Um if com and | Quando as duas condições levam ao mesmo bloco e não há "senão" no meio |
Quando dá errado
else no nível errado (sem mensagem de erro)
A Ana queria que o caixa dissesse "Senha errada." quando a senha estivesse errada. Mas recuou o else 4 espaços a mais:
saldo = 200.0
senha = "1234"
valor = 500.0
if senha == "1234":
if valor <= saldo:
print("Saque feito.")
else:
print("Senha errada.")
$ python3 else_errado.py Senha errada. « a senha estava certa!
Com 4 espaços, o else ficou na coluna do if valor <= saldo, e virou o "senão" dele: a mensagem aparece quando o valor não cabe no saldo. E com a senha errada, o programa não mostra nada, porque o if de fora não tem else. O Python não reclama: o programa está bem escrito, só faz outra coisa. Como consertar: mova o else para a coluna do if a que ele pertence (a régua da coluna).
Missão: aqui a senha está errada, mas o caixa não mostra nada. Conserte o else para que ele pertença ao if da senha. Se quiser, acrescente também o "Saldo insuficiente." no lugar certo.
saldo = 200.0
senha = "9999"
valor = 50.0
if senha == "1234":
if valor <= saldo:
print("Saque feito.")
else:
print("Senha errada.")
saldo = 200.0
senha = "9999"
valor = 50.0
if senha == "1234":
if valor <= saldo:
print("Saque feito.")
else:
print("Saldo insuficiente.")
else:
print("Senha errada.")
senha = input("Senha: ")
if senha == "1234":
valor = float(input("Valor do saque: R$ "))
print(f"Você pediu R$ {valor:.2f}")
$ python3 nameerror.py
Senha: 9999
Traceback (most recent call last):
File "/home/ana/nameerror.py", line 4, in <module>
print(f"Você pediu R$ {valor:.2f}")
^^^^^
NameError: name 'valor' is not defined
line 4, in <module>: o erro aconteceu na linha 4, quando o programa já estava rodando.^^^^^: embaixo devalor.NameError: name 'valor' is not defined: "o nomevalornão está definido". A variável é criada dentro doif, na linha 3. Com a senha errada, a linha 3 nunca rodou, evalornão existe quando a linha 4 tenta usá-la.
Com a senha certa, o mesmo programa funciona. É o tipo de erro que só aparece em um dos caminhos, e por isso é bom testar todos. Como consertar: use a variável só dentro do bloco em que ela foi criada (recue o print), ou dê um valor a ela antes do if (valor = 0.0).
senha = "1234"
valor = 50.0
if senha == "1234":
if valor <= 200:
print("Saque feito.")
$ python3 interno_sem_recuo.py
File "/home/ana/interno_sem_recuo.py", line 5
print("Saque feito.")
^^^^^
IndentationError: expected an indented block after 'if' statement on line 4
O if da linha 4 (de dentro) precisa do seu próprio bloco, com 4 espaços a mais que ele: 8 espaços. O print ficou com 4, no mesmo nível do if. A mensagem diz exatamente qual if ficou sem bloco: o da linha 4.
else numa coluna que não existe
senha = "1234"
valor = 50.0
if senha == "1234":
if valor <= 200:
print("Saque feito.")
else:
print("Saldo insuficiente.")
$ python3 else_torto.py
File "/home/ana/else_torto.py", line 6
else:
^
IndentationError: unindent does not match any outer indentation level
O else ficou com 2 espaços. Acima dele existem if nas colunas 0 e 4, mas nenhum na coluna 2: "o recuo não bate com nenhum nível de fora". O Python não sabe de qual if ele é. Como consertar: ponha o else exatamente na coluna do if dele: 4 espaços para o de dentro, 0 para o de fora.
Referência rápida
| Escrita | O que faz |
|---|---|
if a: com if b: no bloco | A pergunta b só é feita se a for verdadeira |
| +4 espaços por nível | 0 = programa, 4 = dentro do 1º if, 8 = dentro do 2º… |
else na coluna de um if | Pertence a esse if |
if a: → if b:, sem else | O mesmo que if a and b: |
| Mais de 2 ou 3 níveis | Procure achatar com and ou elif |
| Sintoma | Causa provável |
|---|---|
| Mensagem do "senão" errado, sem erro | else na coluna de outro if |
NameError: name '…' is not defined só em alguns casos | A variável é criada dentro de um bloco que nem sempre roda |
IndentationError: expected an indented block after 'if' statement on line N | O bloco do if da linha N (muitas vezes o de dentro) não tem os 4 espaços a mais |
IndentationError: unindent does not match any outer indentation level | Uma linha (muitas vezes um else) numa coluna em que não há bloco |
Exercícios
1. Quantos espaços?
Um print dentro de um if que está dentro de outro if (que está na margem) fica com quantos espaços de recuo?
2. Achate com and
Escreva a palavra que transforma os dois if aninhados (sem else) if chovendo: → if tem_guarda_chuva: num if só:
3. O que este programa mostra?
ingresso = "sim"
idade = 15
if ingresso == "sim":
if idade >= 18:
print("Verde")
else:
print("Azul")
else:
print("Bilheteria")
4. No programa do exercício 3, com ingresso = "não" e idade = 20, o que aparece?
5. Como o Python sabe a qual if um else pertence?
Missão final: o caixa que deixava o saldo negativo
Missão: no caixa da Ana, com a senha certa, qualquer saque é aceito. Com a entrada preparada (senha 1234, valor 500), ele mostra Saque feito. Saldo: R$ -300.00! Dentro do bloco da senha, acrescente um if/else aninhado: só faça o saque se o valor couber no saldo; senão, mostre Saldo insuficiente.
saldo = 200.0
senha = input("Senha: ")
if senha == "1234":
valor = float(input("Valor do saque: R$ "))
saldo = saldo - valor
print(f"Saque feito. Saldo: R$ {saldo:.2f}")
else:
print("Senha errada.")
saldo = 200.0
senha = input("Senha: ")
if senha == "1234":
valor = float(input("Valor do saque: R$ "))
if valor <= saldo:
saldo = saldo - valor
print(f"Saque feito. Saldo: R$ {saldo:.2f}")
else:
print("Saldo insuficiente.")
else:
print("Senha errada.")
Resumo
- Uma condição aninhada é um
ifdentro do bloco de outro: a pergunta de dentro só é feita quando a de fora deuTrue. - Cada nível acrescenta 4 espaços de recuo: 0, 4, 8, 12…
- Um
elsepertence aoifde cima que está na mesma coluna. Na coluna errada ele muda o sentido do programa, sem erro nenhum. - Dois
ifaninhados semelsesão o mesmo que umifcomand; vários níveis com mensagens de erro costumam ficar melhores como escadaelif. - Uma variável criada dentro de um bloco só existe se aquele caminho rodou; usá-la depois pode dar
NameErrorem alguns casos. - Prefira no máximo dois ou três níveis: a "pirâmide" de
ifé difícil de ler.