Pular para conteúdo

8. for e range: repetir para cada

Nesta aula

Ideia central: quando você já sabe quantas voltas o laço tem de dar, o while pede três linhas que dá para esquecer. O for junta as três numa só, e o laço deixa de ter como ficar infinito.

Ao fim você vai conseguir: usar range(n) e range(inicio, fim); escolher entre for e while com um critério e não pelo gosto; pôr um if dentro do laço para contar e classificar; e explicar por que o total impresso dentro do laço aparece cinco vezes.

O contador, de novo

Reveja o laço do capítulo anterior:

dia = 1
while dia <= 5:
    print(f"Dia {dia}: verifique seu consumo")
    dia = dia + 1

Três das quatro linhas existem só para administrar o contador: criar, testar, avançar. E cada uma delas é uma chance de errar — esquecer o avanço, trocar < por <=, começar em zero sem querer.

O for faz as três de uma vez:

# for com range(n): n voltas, comecando em 0.
for i in range(5):
    print("volta numero", i)

print("Fim.")
volta numero 0
volta numero 1
volta numero 2
volta numero 3
volta numero 4
Fim.

Leia em voz alta: "para cada i em range(5), faça isto". A variável i é criada pelo for, recebe um valor novo a cada volta e avança sozinha. Não há i = 0 para escrever nem i = i + 1 para esquecer.

💡 Pense assim: a chamada da turma

O while é o porteiro: "enquanto ainda houver gente na fila, mande entrar o próximo". O for é a chamada: a lista de nomes já existe, e você passa por cada um dela, do primeiro ao último. Quando a lista acaba, acabou.

range(n): de zero a n−1

Duas coisas do exemplo acima pegam todo mundo, e as duas estão na mesma linha da saída:

  • a contagem começa em 0, não em 1;
  • ela termina em 4, não em 5.

range(5) produz 0, 1, 2, 3, 4 — cinco números, que é o que foi pedido. O 5 não aparece: ele é onde a contagem para, não o último valor.

Escrita Valores Quantas voltas
range(3) 0, 1, 2 3
range(5) 0, 1, 2, 3, 4 5
range(1) 0 1
range(0) nenhum nenhuma

A última linha merece atenção: range(0) é um laço que não dá volta nenhuma. O programa não dá erro — ele simplesmente pula o bloco inteiro e segue. Se um laço seu "não fez nada", a primeira suspeita é essa.

💡 Pense assim: o andar térreo

Contar a partir do zero incomoda até você lembrar do elevador: o térreo é o andar 0, e um prédio com "5 andares acima do térreo" tem botões de 0 a 5. O Python conta como o elevador, não como a escada.

range(inicio, fim): começando onde você quiser

Quando 0 não serve, diga onde começar:

# range(inicio, fim): comeca no inicio e PARA ANTES do fim.
for numero in range(1, 11):
    print(f"7 x {numero} = {7 * numero}")
7 x 1 = 7
7 x 2 = 14
7 x 3 = 21
7 x 4 = 28
7 x 5 = 35
7 x 6 = 42
7 x 7 = 49
7 x 8 = 56
7 x 9 = 63
7 x 10 = 70

range(1, 11) produz de 1 a 10. A regra é sempre a mesma e é a única coisa que você precisa decorar deste capítulo:

A regra do range

O primeiro número entra; o segundo não. range(1, 11) vai de 1 a 10.

Para percorrer de 1 a n, escreva range(1, n + 1). Esse + 1 parece feio, e é o jeito certo.

Você quer Escreva
5 voltas, tanto faz o valor range(5)
de 1 a 10 range(1, 11)
de 1 a n range(1, n + 1)
os dias 1 a 30 do mês range(1, 31)

O range só entende inteiros. Passar um decimal dá erro na hora — e este é dos que o Python denuncia:

for i in range(2.5):
    print(i)
TypeError: 'float' object cannot be interpreted as an integer

O acumulador continua o mesmo

Trocar o while pelo for não muda em nada o padrão do capítulo anterior:

# O acumulador do capitulo 7, agora com for.
total = 0

for numero in range(1, 11):
    total = total + numero

print("Soma de 1 ate 10:", total)
Soma de 1 ate 10: 55

Mesmo resultado do cap07_acumulador.py, duas linhas a menos. E a regra inegociável continua valendo: total = 0 fica antes do for, na margem. Dentro do laço, ele zera a cada volta e o programa entrega o último valor sem reclamar de nada.

for ou while?

Não é questão de gosto. O critério é uma pergunta só:

Quando o laço começa, você já sabe quantas voltas ele vai dar?

  • Sei → for. Ele conta sozinho e não tem como ficar infinito.
  • Não sei → while. Quem decide é uma condição que só o tempo de execução responde.
Situação Laço
imprimir a tabuada do 7 for — são 10 voltas
percorrer os 30 dias do mês for — são 30
somar valores até a pessoa digitar 0 while — ninguém sabe quantos
descobrir em quantos dias a franquia acaba while — a resposta é o número de voltas
repetir a pergunta até a resposta ser válida while — pode ser na primeira, pode ser na décima

Repare nos dois casos do meio: "quantos dias a franquia aguenta" é uma pergunta cuja resposta é o número de voltas. Se você soubesse quantas são, não precisaria do programa.

if dentro do laço

Um laço que faz a mesma coisa em todas as voltas é útil. Um laço que olha cada valor e decide é onde o computador começa a trabalhar de verdade.

A estrutura é só indentação: o if mora dentro do for, e o que ele controla mora dentro dele.

# CONTADOR e ACUMULADOR juntos, com um if dentro do laco.
meta_por_dia = 1.5

total = 0
acima_da_meta = 0

for dia in range(1, 6):
    consumo = float(input(f"Consumo do dia {dia} em GB: "))
    total = total + consumo
    if consumo > meta_por_dia:
        acima_da_meta = acima_da_meta + 1
        print(f"  dia {dia}: acima da meta")

print(f"Consumo total: {total:.1f} GB")
print(f"Media por dia: {total / 5:.2f} GB")
print(f"Dias acima da meta: {acima_da_meta}")

Com o cliente informando 1.4, 2.0, 0.6, 3.1 e 1.2 GB, a sessão na tela fica assim:

Consumo do dia 1 em GB: 1.4
Consumo do dia 2 em GB: 2.0
  dia 2: acima da meta
Consumo do dia 3 em GB: 0.6
Consumo do dia 4 em GB: 3.1
  dia 4: acima da meta
Consumo do dia 5 em GB: 1.2
Consumo total: 8.3 GB
Media por dia: 1.66 GB
Dias acima da meta: 2

Há três padrões trabalhando ao mesmo tempo neste laço, e vale separá-los:

Variável Padrão Nasce onde Cresce quando
total acumulador antes do for, valendo 0 toda volta
acima_da_meta contador antes do for, valendo 0 só quando o if dá True
consumo o valor da volta dentro do for é trocado a cada volta

A diferença entre acumulador e contador é uma linha:

total = total + consumo          # acumulador: soma o VALOR
acima_da_meta = acima_da_meta + 1  # contador: soma SEMPRE 1

O contador não sabe nada sobre os valores — ele só sabe quantas vezes a condição foi verdadeira. São os padrões 1 e 2 da tabela da visão geral, e são os que você mais vai usar no semestre que vem.

💡 Pense assim: conferir o extrato

Você passa o dedo pelas linhas do extrato uma a uma. Numa mão, o total gasto — soma todas. Na outra, quantas compras passaram de R$ 100 — soma 1 e só quando passou.

São duas contas diferentes sobre a mesma passada. Por isso as duas variáveis existem antes de o dedo começar a descer.

O outro erro que não dá erro

Os dois laços abaixo são idênticos. A única diferença é a indentação da última linha:

# O MESMO laco, com o print do total dentro e fora.
total = 0
for numero in range(1, 6):
    total = total + numero
    print("dentro do laco:", total)

total = 0
for numero in range(1, 6):
    total = total + numero
print("fora do laco:  ", total)
dentro do laco: 1
dentro do laco: 3
dentro do laco: 6
dentro do laco: 10
dentro do laco: 15
fora do laco:   15

O primeiro imprimiu cinco linhas; o segundo, uma. E o número final é o mesmo nos dois: 15. O cálculo está certo nos dois casos — o que mudou foi quando o programa resolveu falar.

Um print indentado está dentro do laço, então acontece a cada volta. Um print na margem acontece depois que o laço inteiro terminou.

Por que isso é do mesmo tipo do erro do capítulo 7

Porque o programa roda, não reclama, e a saída é plausível: parcialmente certa, com o número certo na última linha.

Se as cinco linhas fossem o consumo de cinco dias, o cliente receberia cinco "totais" diferentes e nenhum aviso de qual é o dele. E se você olhar só a última linha da tela, vai achar que está tudo bem.

Em Python a indentação não é estética. Ela é a única coisa que diz o que está dentro e o que está fora.

Erros comuns deste capítulo

Mensagem ou sintoma Causa provável
o laço deu uma volta a menos range(1, n) em vez de range(1, n + 1)
a contagem começou em 0 e você queria 1 range(n) em vez de range(1, n + 1)
o laço não fez nada range(0), ou um range cujo fim é menor que o início
TypeError: 'float' object cannot be interpreted as an integer passou decimal ao range; use int(...)
o total aparece várias vezes o print está indentado, dentro do laço
o total é igual ao último valor o acumulador foi zerado dentro do laço
IndentationError: expected an indented block after 'for' faltou indentar o corpo do laço
o contador contou todas as voltas o + 1 está fora do if, ou o if está fora do for

Resumo

  • for variavel in range(...): repete um número conhecido de voltas, e cuida do contador sozinho.
  • range(n) vai de 0 a n−1. range(inicio, fim) começa no início e para antes do fim. De 1 a n é range(1, n + 1).
  • Sabe quantas voltas? for. Não sabe? while.
  • Acumulador soma o valor; contador soma 1, dentro de um if. Os dois nascem antes do laço.
  • A indentação decide o que acontece a cada volta e o que acontece no fim. Um print no lugar errado não dá erro — só mente.

Para praticar

Lista 08 · Repetição com for.

Com o for, o while e o if você já resolve a maior parte dos problemas deste semestre. O que ainda falta é um jeito de guardar muitos valores ao mesmo tempo — hoje cada volta do laço joga fora o valor anterior. É a Unidade 4.