Fundamentos
O laço while em Python: repetição com teste no início
Aprenda o laço while em Python: as quatro peças, os padrões de contador, sentinela e bandeira, as condições compostas e os erros que geram laços infinitos.
Por Prof. Rodrigo Faustino · Atualizado em · 14 min de leitura
O while repete um bloco de código enquanto uma condição for verdadeira, e o teste acontece antes de cada volta, inclusive da primeira. Por isso o bloco pode rodar muitas vezes, uma vez ou nenhuma. Para o laço terminar, alguma coisa dentro dele precisa mudar o resultado do teste. Quando isso acontece, o programa sai do bloco e continua na primeira linha sem recuo; quando não acontece, o laço roda para sempre.
O artigo anterior mostrou por que os laços existem e quais perguntas todo laço responde. Este é dedicado ao while: as quatro peças que o formam, os três padrões que resolvem a maior parte dos problemas, as condições com and e not, o or que gera laços infinitos, o while dentro de outro e o uso na ESP32.
As quatro peças
Um while bem escrito tem quatro peças, e a figura as numera na ordem em que o Python as executa:
i = 1
while i <= 5:
print("2 x", i, "=", 2 * i)
i += 1
print("fim")A saída é a tabuada do 2 até o quinto termo, de 2 x 1 = 2 a 2 x 5 = 10, e depois fim. As peças são:
- O valor inicial,
i = 1, que fica antes do laço e cria a variável que o teste vai olhar. - O teste,
i <= 5, que o Python avalia antes de cada volta. Se derTrue, entra no bloco; se derFalse, pula para depois dele. - O corpo, o
print, que é o trabalho repetido. - A atualização,
i += 1, que muda a variável para que o teste, em algum momento, dêFalse.
A peça 5 da figura, o print("fim") sem recuo, não é do laço. Ela roda uma vez, quando o teste falha. Quem aprende o while costuma errar a posição de uma dessas peças: o valor inicial dentro do laço, a atualização fora dele, ou o teste que não olha a variável que muda.
O laço que não roda nenhuma vez
Como o teste vem antes do corpo, um while cuja condição já começa falsa não executa o bloco:
n = 0
while n > 0:
print("nunca aparece")
n = n - 1
print("o laco nao rodou, n vale", n)A saída é só o laco nao rodou, n vale 0. Isso é uma característica útil, não um defeito: um programa que soma os valores digitados e recebe zero logo de início deve somar nada e responder 0, sem precisar de um if especial. O while com teste no início trata esse caso de graça. Existe outro tipo de laço, que roda o corpo antes de testar, e o Python não tem uma palavra própria para ele. O artigo sobre o "faça-enquanto" mostra como simulá-lo.
A IA que lembra da sua vida e mora no seu computador
- Memória de longo prazo com a fonte de cada resposta
- Funciona offline: seus dados ficam no seu PC
- Lê PDFs, slides, fotos e gravações de reunião
Plano Essencial grátis para sempre
Três padrões que resolvem quase tudo
A maioria dos while que se escreve no começo cai num destes padrões. Reconhecer o padrão ajuda a escrever o laço sem tentativa e erro.
O contador
Quando se sabe quantas voltas dar, uma variável conta até o limite. É o padrão da tabuada acima: valor inicial, teste contra o limite e += 1 no fim do bloco. O contador pode crescer, diminuir (n -= 1) ou andar de dois em dois (i += 2), e o teste usa <, <=, > ou >= conforme o sentido. Para esse padrão, o for com range() costuma ser mais curto, e é o assunto do próximo artigo da série.
A sentinela
Quando é o usuário quem decide quando parar, o programa não sabe de antemão quantas voltas serão necessárias. Um valor combinado, a sentinela, avisa o fim. O exemplo calcula a média de notas, e o -1 encerra a lista:
soma = 0
contador = 0
nota = float(input("Nota (-1 para parar): "))
while nota != -1:
soma = soma + nota
contador = contador + 1
nota = float(input("Nota (-1 para parar): "))
if contador > 0:
print("media", soma / contador)
else:
print("nenhuma nota")Com as entradas 8, 6.5, 9 e -1, a última linha da saída é media 7.8333336. O Python do computador mostraria 7.833333333333333, a mesma conta com o float de 64 bits (o simulador usa 32 bits, como a placa). Se a primeira nota digitada já for -1, o laço não roda, o contador fica em 0 e o programa imprime nenhuma nota. O if contador > 0 existe por isso: sem ele, a divisão soma / contador seria uma divisão por zero. O desafio Média de N usa uma variação: o primeiro número lido diz quantos valores virão depois, e o laço é um contador.
Repare na leitura, que aparece duas vezes. A primeira, antes do laço, dá ao teste o valor com que comparar. A segunda, na última linha do bloco, é a atualização do padrão: ela é o que muda a cada volta. Quem escreve só a primeira leitura monta um laço que lê uma vez e repete para sempre o mesmo valor.
A bandeira
Às vezes o laço depende de um estado do programa, e não de um número. Uma variável booleana, a bandeira, guarda esse estado e vira False quando a repetição deve acabar:
carga = 100
ligado = True
while ligado:
carga = carga - 30
print("carga", carga)
if carga <= 20:
ligado = False
print("desligado com", carga)A saída é carga 70, carga 40, carga 10 e desligado com 10. O while ligado: dispensa a comparação, porque ligado já é um booleano. Quem decide parar é o if dentro do corpo, e note que a volta em que a carga chega a 10 termina normalmente: o teste só é feito de novo no início da volta seguinte. Esse padrão aparece em jogos (a partida continua enquanto o jogador tiver vidas), em menus (o menu se repete enquanto o usuário não escolher sair) e em programas de placa (o aparelho funciona enquanto não houver erro).
Uma condição que consome o valor
Um quarto jeito é o laço em que a própria variável do teste vai sendo gasta. A contagem de dígitos de um número é o exemplo clássico, e usa a divisão inteira e o resto vistos no artigo sobre operadores aritméticos:
n = 4821
digitos = 0
soma = 0
while n > 0:
soma = soma + n % 10
n = n // 10
digitos = digitos + 1
print(digitos, soma, n)A saída é 4 15 0. O n % 10 pega o último algarismo, e o n // 10 o descarta. A cada volta o número encolhe: 4821, 482, 48, 4, 0. Quando ele chega a 0, o teste n > 0 falha. O programa contou 4 dígitos, somou 4 + 8 + 2 + 1 = 15 e deixou n zerado, o que mostra que o laço destrói o valor original. Se o número precisar ser usado depois, guarde uma cópia numa variável antes do laço.
Condições compostas: and, not e a conta de tentativas
A condição do while é uma expressão booleana como as do if, e aceita and, or e not. Um uso muito comum é combinar "ainda há tentativas" com "ainda não acertou", e o exemplo da senha mostra os dois:
tentativas = 0
acertou = False
while tentativas < 3 and not acertou:
senha = input("Senha: ")
tentativas = tentativas + 1
if senha == "1234":
acertou = True
else:
print("senha errada")
if acertou:
print("acesso liberado")
else:
print("bloqueado")Com as entradas 1111 e 1234, o programa mostra senha errada e depois acesso liberado. Se as três senhas forem erradas (1111, 2222 e 3333), ele mostra senha errada três vezes e termina com bloqueado. O laço tem duas razões para parar, e cada uma é uma metade da condição: acabaram as tentativas ou o usuário acertou. O and exige que as duas continuem verdadeiras para repetir. Depois do laço, o if acertou descobre qual das duas razões encerrou a repetição, um truque que serve para qualquer laço com duas saídas. O desafio Senha 1234 é a versão mais simples dessa ideia, sem limite de tentativas: repete a leitura até a senha certa.
Da ementa ao semestre planejado
- Plano de ensino e calendário montados sozinhos
- Diário de aulas pronto para colar no SIGA
- Slides e listas de exercícios com gabarito
Versão Community grátis · Windows
O erro do or
A pergunta "repita enquanto a resposta não for s nem n" é uma armadilha de lógica, e quase todo mundo a escreve errado pelo menos uma vez, porque a frase em português tem "nem" e o código pede and. A tabela da figura mostra a conta:
for resp in ("s", "n", "x"):
print(resp, resp != "s" or resp != "n", resp != "s" and resp != "n", resp not in ("s", "n"))A saída é s True False False, n True False False e x True True True. A segunda coluna, a do or, dá True nas três linhas. Quem digita s passa no teste resp != "n", e quem digita n passa no teste resp != "s", então nenhuma resposta faz o laço parar, nem a resposta certa. O and e o not in dão False para s e para n, e True só para a resposta inválida. A versão correta, com a mensagem de erro e a nova leitura dentro do laço, é esta:
resp = input("Continuar (s/n)? ")
while resp != "s" and resp != "n":
print("Responda s ou n")
resp = input("Continuar (s/n)? ")
print("resposta", resp)Com as entradas x, q e s, a saída pede a resposta de novo duas vezes e termina com resposta s. É a mesma situação das tabelas-verdade: quando a condição parece certa mas o programa se comporta mal, monte a tabela com os valores possíveis. As leis de De Morgan, tratadas nesse artigo, explicam por que "não s e não n" é o mesmo que "não (s ou n)".
Um while dentro de outro
O corpo de um while pode conter outro while. O laço de dentro roda completo a cada volta do de fora, e o resultado é uma grade:
i = 1
while i <= 3:
j = 1
while j <= 3:
print(i * j, end=" ")
j += 1
print()
i += 1A saída é a tabuada de 1 a 3 em três linhas: 1 2 3, 2 4 6 e 3 6 9. O end=" " troca a quebra de linha do print por um espaço, para os números ficarem lado a lado, e o print() vazio, no recuo do laço de fora, quebra a linha ao fim de cada fileira. Repare que o j = 1 fica dentro do laço de fora: ele precisa voltar a 1 em cada fileira. Esquecer isso, ou colocar o j = 1 antes dos dois laços, é o defeito clássico, porque na segunda fileira o j já vale 4 e o laço de dentro não roda nenhuma vez.
O que muda na ESP32
O while do MicroPython é o mesmo do Python do computador. Dois usos aparecem o tempo todo em programas de placa. O primeiro é o laço principal, o while True: do main.py, que lê sensores, decide e age até a placa ser desligada. Ele precisa de uma pausa com time.sleep ou time.sleep_ms dentro do corpo, senão roda o mais rápido que o processador deixar. O artigo sobre programar sem travar mostra como fazer várias tarefas dentro dele.
O segundo é esperar por algo com limite de tempo, uma espera com timeout. O teste compara o tempo que passou com um limite:
import time
inicio = time.ticks_ms()
voltas = 0
while time.ticks_diff(time.ticks_ms(), inicio) < 200:
voltas = voltas + 1
time.sleep_ms(50)
print("pelo menos 3 voltas:", voltas >= 3)A saída é pelo menos 3 voltas: True. A função time.ticks_ms() devolve um contador de milissegundos, e time.ticks_diff calcula a diferença entre dois valores sem se confundir quando o contador dá a volta, o que o - simples não garante, como o artigo sobre ticks explica. O laço repete enquanto menos de 200 ms se passaram. O programa imprime só se houve pelo menos três voltas, e não o número exato, porque ele muda de uma execução para outra, e na placa também depende da velocidade da leitura. É a base de esperas como "aguarde a resposta do sensor por até dois segundos". Um laço de espera sempre precisa de uma saída por tempo, para a placa não ficar presa a um sensor que nunca responde.
Os laços com float pedem o cuidado do artigo anterior: comparar com == ou != um valor acumulado de 0,1 em 0,1 pode nunca dar certo, e uma contagem de voltas inteira como trava é a defesa mais simples.
Em sala de aula: onde o while costuma tropeçar
Os casos abaixo se repetem nas turmas, e os de laço infinito são os que mais chamam o professor. Em todos o programa roda, e o que falha é o comportamento.
A atualização fora do laço
A linha de atualização sai do recuo e o teste nunca muda:
i = 1
voltas = 0
while i <= 3 and voltas < 5:
print("i vale", i)
voltas += 1
i = i + 1
print("voltas", voltas, "i", i)A saída tem cinco linhas i vale 1, depois voltas 5 i 2. O i = i + 1 está na margem, depois do laço, então roda uma vez só, no fim. O i fica em 1 durante todo o laço. Sem a trava do voltas, o programa imprimiria i vale 1 para sempre. A trava é uma boa prática de depuração: um contador de segurança que corta o laço no valor esperado mais uma folga.
O sinal de igual no teste
O = é atribuição e o == é comparação, e um while n = 0: não funciona. As mensagens variam:
| Erro | Simulador (MicroPython) | Python no computador |
|---|---|---|
while n = 0: | SyntaxError: invalid syntax (linha 2) | SyntaxError: invalid syntax. Maybe you meant '==' or ':=' instead of '='? |
while n > 0 sem os dois-pontos | SyntaxError: invalid syntax (linha 2) | SyntaxError: expected ':' |
| corpo sem recuo | SyntaxError: invalid syntax (linha 3) | IndentationError: expected an indented block after 'while' statement on line 2 |
O simulador diz só invalid syntax e a linha. A pista é olhar a linha indicada: o = onde devia haver ==, os dois-pontos que faltam no fim da linha do while e a linha seguinte que não está recuada. O artigo sobre if e else trata dos erros de recuo com mais detalhe.
A segunda leitura que não existe
No padrão da sentinela, quem lê o valor só antes do laço fica com um laço infinito: a variável do teste nunca muda. É o mesmo erro da atualização esquecida, com uma desculpa mais difícil de enxergar, porque o input() fica logo acima do while e dá a impressão de que a leitura "já está lá". A pergunta de teste é: onde, dentro do bloco, o valor de nota muda?
Esquecer o caso de zero voltas
A média sem nenhuma nota, a soma de uma lista vazia, a senha de um usuário que desiste antes de começar. Se o programa divide pelo contador, o if contador > 0 do exemplo da média existe para isso. O teste que vale fazer em todo while é a primeira volta já falsa.
O or no lugar do and
O erro da figura, com a tabela-verdade. A frase em português "enquanto não for s nem n" é um and, e o or produz um laço que nunca termina, e que passa sem nenhum aviso.
O j que não volta ao início
Em laços aninhados, a variável do laço de dentro precisa ser reiniciada a cada volta do de fora. O sintoma é a segunda fileira da grade vazia, sem erro nenhum.
Exercício: adivinhe o número
O programa sorteia (aqui, fixa) um número secreto e o jogador chuta até acertar. A cada chute errado, o programa diz se o segredo é maior ou menor, e no fim informa quantas tentativas foram necessárias. Reúne a sentinela (o acerto é o fim), um if dentro do laço e um contador.
segredo = 65
palpite = int(input("Palpite: "))
tentativas = 1
while palpite != segredo:
if palpite < segredo:
print("maior")
else:
print("menor")
palpite = int(input("Palpite: "))
tentativas = tentativas + 1
print("acertou em", tentativas, "tentativas")Com os palpites 50, 75, 62, 68 e 65, a saída alterna maior, menor, maior, menor e termina com acertou em 5 tentativas. O contador começa em 1 porque o primeiro palpite é lido antes do laço, e cada leitura dentro do laço soma mais uma tentativa. Para ampliar, acrescente um limite de tentativas na condição, while palpite != segredo and tentativas < 7, e uma mensagem de derrota depois do laço, como no exemplo da senha.
Perguntas frequentes
Qual a diferença entre while e if?
O if testa uma vez e segue em frente. O while volta ao teste depois de cada execução do bloco e só segue quando ele falha.
Quando usar while e quando usar for?
Use for quando já se sabe o que percorrer (os números de 1 a 10, os itens de um grupo). Use while quando o fim depende de algo que só aparece rodando, como uma resposta do usuário, uma leitura de sensor ou uma condição que muda sozinha.
O que é while True?
É um laço cuja condição nunca fica falsa. Ele termina por um break dentro do corpo ou quando o programa é interrompido. É a estrutura do laço principal da ESP32, e o artigo sobre break e continue mostra os outros usos.
O while pode ter else?
Pode, e o bloco do else roda quando o teste falha, mas não quando o laço é interrompido por break. O assunto é do artigo sobre break, continue e o else dos laços.
Como descubro por que o meu laço não termina?
Coloque um print com a variável do teste dentro do laço e acompanhe os valores, como na tabela de acompanhamento do artigo anterior. Se o valor não muda, falta a atualização. Se muda mas nunca chega ao limite, o sentido está errado ou a condição está mal escrita.
Para continuar
A trilha Lógica com Python tem os desafios de repetição. O Até zero é a sentinela mais simples, a Soma dinâmica soma valores com a sentinela, a Senha 1234 repete a leitura até acertar, e a Média de N combina contador e acumulador. Para a base, releia Por que repetir.
O próximo assunto é o laço for e a função range(): a forma curta de repetir um número conhecido de vezes, sem escrever as quatro peças à mão.