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).

Você vai aprender
  • A escrever um if (com ou sem else) 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 if cada else pertence, pela coluna.
  • Quando o aninhamento pode virar um and ou uma escada elif, e por que a "pirâmide" de if é difícil de ler.
  • Os erros reais: o else no nível errado (que não dá erro nenhum), o NameError de uma variável criada só num caminho e os IndentationError.

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:

  1. "Você tem ingresso?" Se não: "Compre na bilheteria", e a conversa acaba aí.
  2. 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 if de fora (na margem, 0 espaços).
idade = int(input(…))
4 espaços: está dentro do bloco do if de fora. Só roda para quem respondeu "sim".
if idade >= 18:
O if de 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 if de 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" do if de 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:

RecuoOnde a linha estáNo show.py
0 espaçosNo programa principal: roda sempreingresso = input(…), if ingresso == "sim":, o último else:
4 espaçosDentro do primeiro if (ou do seu else)idade = …, if idade >= 18:, print("Pode entrar…")
8 espaçosDentro do segundo if, que está dentro do primeiroOs dois print das pulseiras
A régua da coluna

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
simsimSaque feito
simnãoSaldo 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.")
FormaQuando usar
AninhadaQuando 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 elifQuando são faixas ou casos de um mesmo valor. Costuma ficar mais curta e toda na mesma coluna
Um if com andQuando as duas condições levam ao mesmo bloco e não há "senão" no meio

Quando dá errado

O 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.")
Uma variável que só existe num caminho
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 de valor.
  • NameError: name 'valor' is not defined: "o nome valor não está definido". A variável é criada dentro do if, na linha 3. Com a senha errada, a linha 3 nunca rodou, e valor nã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).

O bloco de dentro sem recuo
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.

Um 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

EscritaO que faz
if a: com if b: no blocoA pergunta b só é feita se a for verdadeira
+4 espaços por nível0 = programa, 4 = dentro do 1º if, 8 = dentro do 2º…
else na coluna de um ifPertence a esse if
if a: → if b:, sem elseO mesmo que if a and b:
Mais de 2 ou 3 níveisProcure achatar com and ou elif
SintomaCausa provável
Mensagem do "senão" errado, sem erroelse na coluna de outro if
NameError: name '…' is not defined só em alguns casosA variável é criada dentro de um bloco que nem sempre roda
IndentationError: expected an indented block after 'if' statement on line NO 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 levelUma 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?

Resposta: espaços

2. Achate com and

Escreva a palavra que transforma os dois if aninhados (sem else) if chovendo: → if tem_guarda_chuva: num if só:

if chovendo tem_guarda_chuva:

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 if dentro do bloco de outro: a pergunta de dentro só é feita quando a de fora deu True.
  • Cada nível acrescenta 4 espaços de recuo: 0, 4, 8, 12…
  • Um else pertence ao if de cima que está na mesma coluna. Na coluna errada ele muda o sentido do programa, sem erro nenhum.
  • Dois if aninhados sem else são o mesmo que um if com and; vários níveis com mensagens de erro costumam ficar melhores como escada elif.
  • Uma variável criada dentro de um bloco só existe se aquele caminho rodou; usá-la depois pode dar NameError em alguns casos.
  • Prefira no máximo dois ou três níveis: a "pirâmide" de if é difícil de ler.