Python range()
Na aula for, você viu que o for percorre sequências: as letras de um texto, os itens de uma lista. Mas e para contar de 1 até 100? Escrever uma lista com cem números à mão não tem graça. Para isso existe a função range() (em inglês, "faixa", "intervalo"): ela fabrica uma sequência de números para o for percorrer. Você diz onde começa, onde termina e de quanto em quanto pular.
- As três formas do
range(): com o fim; com o início e o fim; com início, fim e passo. - A regra que mais confunde: o fim não entra. E por que ela é assim.
- A contar de 5 em 5, só os pares, e para trás, com passo negativo.
- A ver os números de um
rangecomlist(range(…)). - A repetir algo N vezes, inclusive um N digitado pelo usuário.
- Os erros reais: passo zero, número com vírgula, o texto do
input()e orangevazio que não avisa nada.
Todos os programas desta aula rodaram no Python 3.14 da máquina da Ana (usuária ana, computador notebook), com python3 arquivo.py; as linhas com >>> foram digitadas no modo interativo.
A ideia: as senhas da padaria
A padaria do bairro tem uma máquina de senhas. Às 7 horas, o funcionário anota no quadro: "hoje de manhã, as senhas vão da 1 até antes da 6". Saem as senhas 1, 2, 3, 4 e 5. A 6 é a primeira que não é atendida de manhã: ela marca onde a faixa para.
O range() funciona exatamente assim. Você dá a ele:
- o início: o primeiro número que entra;
- o fim: o número onde a faixa para, que não entra;
- o passo (opcional): de quanto em quanto pular.
1. range(fim): só o fim
Com um número só, o range começa do zero e para antes do número dado:
for numero in range(5):
print(numero)
$ python3 range5.py 0 1 2 3 4
Cinco números, de 0 a 4. O 5 não aparece. Pode parecer estranho, mas tem uma vantagem: range(5) dá exatamente 5 voltas. Quer repetir algo 10 vezes? range(10). O número que você escreve é a quantidade de voltas.
Começar do zero também não é capricho: no Python, as posições de um texto e de uma lista começam do 0 (lembra dos índices?). O range(5) dá justamente as posições de algo com 5 itens: 0, 1, 2, 3 e 4.
2. range(início, fim): escolhendo onde começa
Para começar de outro número, ponha o início antes do fim, separados por vírgula. As senhas da padaria:
for senha in range(1, 6):
print(f"Senha {senha}, por favor!")
$ python3 senhas.py Senha 1, por favor! Senha 2, por favor! Senha 3, por favor! Senha 4, por favor! Senha 5, por favor!
- range
- A função que fabrica a sequência de números.
- 1
- O início: o primeiro número, que entra.
- ,
- A vírgula separa os valores (os argumentos) que você passa à função.
- 6
- O fim: onde a sequência para. O 6 não entra; o último número é o 5.
Para ir de A até B, incluindo o B, escreva range(A, B + 1). De 1 a 10: range(1, 11). De 1 a 100: range(1, 101). E range(A, B) sempre tem B − A números: range(1, 6) tem 6 − 1 = 5.
Somando de 1 a 100
Na aula while, somar uma sequência pedia contador, condição e passo. Com for e range, o laço fica assim:
soma = 0
for numero in range(1, 101):
soma += numero
print(f"1 + 2 + ... + 100 = {soma}")
$ python3 soma100.py 1 + 2 + ... + 100 = 5050
O range(1, 101) entrega os números de 1 a 100, um por volta, e o acumulador soma vai juntando.
3. range(início, fim, passo): pulando de tanto em tanto
O terceiro número é o passo: de quanto em quanto a sequência anda. Sem ele, o passo é 1. A Ana põe um bolo no forno por meia hora e quer conferir de 5 em 5 minutos:
for minuto in range(0, 31, 5):
print(f"{minuto} minutos")
$ python3 cinco_em_cinco.py 0 minutos 5 minutos 10 minutos 15 minutos 20 minutos 25 minutos 30 minutos
Começa no 0 e soma 5 a cada volta: 0, 5, 10… até 30. O próximo seria 35, que já passa do fim (31); aí a sequência para. Repare que o fim é 31, e não 30: com range(0, 30, 5), o 30 ficaria de fora.
Com passo 2, começando de um número par, saem só os pares:
for numero in range(2, 11, 2):
print(numero, end=" ")
print()
$ python3 pares.py 2 4 6 8 10
Missão: mostre os múltiplos de 3, de 3 até 30 (incluindo o 30), um por linha. Mude só os números do range: o início, o fim e o passo.
for numero in range(1, 11):
print(numero)
for numero in range(3, 31, 3):
print(numero)
4. Contar para trás: passo negativo
Com um passo negativo, a sequência anda para trás. Aí o início é o número maior, e o fim, o menor:
for segundo in range(5, 0, -1):
print(f"{segundo}...")
print("Já!")
$ python3 regressiva_range.py 5... 4... 3... 2... 1... Já!
A regra do fim continua valendo: o 0 é onde a contagem para, e ele não entra. Para incluir o zero, o fim teria de ser -1: range(5, -1, -1).
Missão: é réveillon. Faça a contagem regressiva de 10 até 1, um número por linha, e depois o Feliz Ano Novo!.
for numero in range(1, 11):
print(numero)
print("Feliz Ano Novo!")
for numero in range(10, 0, -1):
print(numero)
print("Feliz Ano Novo!")
5. Vendo os números: list(range(…))
Se você mostrar um range direto, o Python não lista os números; ele mostra só a "receita":
>>> range(5) range(0, 5)
Isso acontece porque o range não guarda os números: ele calcula cada um na hora em que o for pede. É por isso que até um range(1000000) ocupa quase nada na memória. Para ver a sequência inteira, transforme-a numa lista com list():
>>> list(range(5)) [0, 1, 2, 3, 4] >>> list(range(1, 6)) [1, 2, 3, 4, 5] >>> list(range(0, 21, 5)) [0, 5, 10, 15, 20] >>> list(range(5, 0, -1)) [5, 4, 3, 2, 1] >>> list(range(5, 0)) [] >>> len(range(1, 6)) 5 >>> sum(range(1, 101)) 5050
Essa é a melhor forma de tirar dúvida sobre um range: antes de pôr no for, olhe os números com list(). Repare em três linhas:
list(range(5, 0))deu[], uma lista vazia: de 5 até 0 andando de 1 em 1 para frente, não há número nenhum. Para trás, só com passo negativo.len(range(1, 6))diz quantos números há, sem precisar listá-los: 5.sum(range(1, 101))soma a sequência inteira de uma vez: o mesmo 5050 do laço da seção 2. A funçãosum()("soma") tem mais detalhes em Funções Embutidas.
Experimente: mude os números e rode para ver a sequência. Tente prever o resultado antes: range(10), range(3, 8), range(1, 20, 4), range(10, 0, -3), range(8, 3).
print(list(range(2, 15, 3)))
6. Repetir N vezes
Muitas vezes você nem precisa do número: só quer repetir. Quando a variável do laço não vai ser usada, o costume é chamá-la de _ (um sublinhado sozinho), que quer dizer "não interessa":
for _ in range(3):
print("Hip, hip, hurra!")
$ python3 hurra.py Hip, hip, hurra! Hip, hip, hurra! Hip, hip, hurra!
E a quantidade pode vir do usuário. Como o input() devolve texto, converta com int() antes de passar ao range (aula Conversão de Tipos):
vezes = int(input("Quantas vezes? "))
for volta in range(vezes):
print(f"Volta {volta + 1} de {vezes}")
$ python3 quantas.py Quantas vezes? 3 Volta 1 de 3 Volta 2 de 3 Volta 3 de 3
O range(3) deu 0, 1 e 2; o volta + 1 mostra 1, 2 e 3, que é como as pessoas contam.
Formas diferentes de fazer a mesma coisa
Contar de 1 a 5 tem várias escritas. Todas dão 1 2 3 4 5:
| Forma | Quando usar |
|---|---|
for n in range(1, 6): | A mais comum: diga onde começa e onde para (o fim é 6 para incluir o 5) |
for n in range(5): e usar n + 1 | Quando o importante é "5 voltas" e o número da volta é só para mostrar |
n = 1 / while n <= 5: / n += 1 | Funciona, mas tem mais peças para errar; deixe o while para quando não se sabe quantas voltas vão ser |
for n in [1, 2, 3, 4, 5]: | Só para poucos números escolhidos à mão (ex.: [2, 3, 5, 7]); para faixas, use range |
E para percorrer uma lista com o número da posição, dá para combinar range e len:
compras = ["pão", "leite", "café"]
for posicao in range(len(compras)):
print(f"{posicao + 1}. {compras[posicao]}")
$ python3 indice.py 1. pão 2. leite 3. café
Funciona: len(compras) é 3, e range(3) dá as posições 0, 1 e 2. Mas o Python tem uma ferramenta feita para isso, mais clara, o enumerate(), que você vai ver em enumerate() e zip().
Quando dá errado
for numero in range(1, 10):
print(numero, end=" ")
print()
$ python3 ate10.py 1 2 3 4 5 6 7 8 9
Sem mensagem de erro: o Python fez exatamente o que foi pedido. O fim não entra, então range(1, 10) para no 9. É o erro mais comum com range, tão comum que tem nome: erro "por um" (em inglês, off-by-one). Como consertar: fim = último número + 1: range(1, 11).
for segundo in range(5, 0):
print(f"{segundo}...")
print("Já!")
$ python3 vazio.py Já!
Nenhum número, nenhum erro: o laço deu zero voltas. Sem o terceiro número, o passo é +1, e não existe caminho de 5 até 0 andando para frente. O range ficou vazio (list(range(5, 0)) é []). Como consertar: range(5, 0, -1).
for numero in range(1, 10, 0):
print(numero)
$ python3 passo0.py
Traceback (most recent call last):
File "/home/ana/passo0.py", line 1, in <module>
for numero in range(1, 10, 0):
~~~~~^^^^^^^^^^
ValueError: range() arg 3 must not be zero
"Erro de valor: o argumento 3 do range() não pode ser zero". Com passo zero, a sequência nunca sairia do 1; em vez de criar um laço infinito, o Python recusa. Os ~~~~~^^^^^^^^^^ marcam a chamada do range na linha 1. Como consertar: use um passo diferente de zero (1, 2, −1…).
for valor in range(0, 1, 0.1):
print(valor)
$ python3 decimal.py
Traceback (most recent call last):
File "/home/ana/decimal.py", line 1, in <module>
for valor in range(0, 1, 0.1):
~~~~~^^^^^^^^^^^
TypeError: 'float' object cannot be interpreted as an integer
"Erro de tipo: um objeto float (número com casas decimais) não pode ser interpretado como inteiro". O range só trabalha com números inteiros: início, fim e passo. Como consertar: conte com inteiros e divida dentro do laço. Para ir de 0.0 a 0.9 de 0.1 em 0.1: for n in range(10): e use n / 10.
input() direto
vezes = input("Quantas vezes? ")
for volta in range(vezes):
print("Oi!")
$ python3 texto.py
Quantas vezes? 3
Traceback (most recent call last):
File "/home/ana/texto.py", line 2, in <module>
for volta in range(vezes):
~~~~~^^^^^^^
TypeError: 'str' object cannot be interpreted as an integer
A mesma família do erro anterior, agora com str (texto): o input() devolveu o texto '3', e o range quer um número inteiro. Como consertar: vezes = int(input("Quantas vezes? ")).
Referência rápida
| Escrita | Números | O que faz |
|---|---|---|
range(5) | 0, 1, 2, 3, 4 | Do 0 até antes do fim; dá exatamente 5 voltas |
range(1, 6) | 1, 2, 3, 4, 5 | Do início até antes do fim |
range(0, 31, 5) | 0, 5, 10, …, 30 | De 5 em 5 |
range(2, 11, 2) | 2, 4, 6, 8, 10 | Os pares de 2 a 10 |
range(5, 0, -1) | 5, 4, 3, 2, 1 | Para trás: passo negativo, início maior que o fim |
range(5, 0) | (nenhum) | Vazio: para frente não há caminho de 5 a 0 |
list(range(…)) | — | Mostra os números como uma lista |
len(range(…)) / sum(range(…)) | — | Quantos números há / a soma deles |
for _ in range(n): | — | Repetir n vezes sem usar o número |
| Sintoma | Causa provável |
|---|---|
| Faltou o último número | O fim não entra: use fim = último + 1 |
| O laço não roda nenhuma vez, sem erro | Início maior que o fim sem passo negativo (ou o contrário) |
ValueError: range() arg 3 must not be zero | Passo zero |
TypeError: 'float' object cannot be interpreted as an integer | Número com casas decimais no range |
TypeError: 'str' object cannot be interpreted as an integer | Texto (do input()) no range: faltou o int() |
Exercícios
1. De 1 a 10
Complete para o laço passar pelos números de 1 a 10, incluindo o 10:
2. O último número
Qual é o último número de range(0, 20, 4)?
3. Quantos números?
Quantos números tem range(3, 10)?
4. O que list(range(4)) mostra?
5. Qual range faz a contagem 3, 2, 1?
6. for i in range(10, 1): não mostrou nada e não deu erro. Por quê?
Missão final: a soma dos pares
Missão: some todos os números pares de 1 a 100 (2 + 4 + 6 + … + 100). Escreva um for com um range de passo 2 no lugar do comentário, juntando cada número no total.
total = 0
# escreva o for aqui
print(f"Soma dos pares de 1 a 100: {total}")
total = 0
for numero in range(2, 101, 2):
total += numero
print(f"Soma dos pares de 1 a 100: {total}")
No lab, saiu Soma dos pares de 1 a 100: 2550. Para conferir de outro jeito, rode print(sum(range(2, 101, 2))).
Resumo
range()fabrica uma sequência de números inteiros para oforpercorrer.range(fim)começa do 0;range(início, fim)começa do início;range(início, fim, passo)pula de passo em passo.- O fim nunca entra. Para incluir o B, use
range(A, B + 1).range(n)dá exatamente n voltas. - Para trás, passo negativo e início maior:
range(5, 0, -1). Sem o passo negativo, orangefica vazio, sem aviso. list(range(…))mostra os números; use para tirar dúvida antes de pôr nofor.- Só inteiros: passo zero dá
ValueError;floatou texto dãoTypeError(converta oinput()comint()).