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:
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.")
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:
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)
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 ané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
printno lugar errado não dá erro — só mente.
Para praticar¶
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.