Python Iteradores
Desde a aula for, você percorre listas, textos, dicionários e até arquivos com o mesmo for item in coisa:. Nunca precisou dizer "comece do primeiro", "agora o próximo", "pare no último". Quem faz esse trabalho escondido é o iterador (do inglês iterate, "repetir, passar um por um"). Nesta aula você vai abrir o for e ver as peças lá dentro: iter(), next() e o StopIteration. Depois, vai construir o seu próprio iterador.
- A diferença entre iterável (a coisa que dá para percorrer) e iterador (quem percorre).
- A pedir um iterador com
iter()e o próximo item comnext(). - O que é o
StopIteratione por que você quase nunca o vê. - O que o
forfaz por dentro, passo a passo. - Por que um iterador se gasta e uma lista não.
- A criar o seu iterador com os métodos
__iter__e__next__. - Os erros reais:
'list' object is not an iterator,object is not iterable,iter() returned non-iteratore o laço que nunca acaba.
A ideia: o livro e o marcador de página
Pense num livro de receitas. O livro tem todas as páginas, do começo ao fim, mas não sabe em qual página você parou. Para isso existe o marcador de página: ele lembra onde você está, e cada vez que você pede "a próxima", ele avança uma página. Quando o livro acaba, o marcador avisa: "não tem mais".
- O livro é o iterável: uma lista, um texto, um dicionário. Ele guarda os itens e sabe criar um marcador novo sempre que alguém pede.
- O marcador é o iterador: ele só sabe uma coisa, entregar o próximo item, e lembra onde parou.
- Um livro pode ter vários marcadores ao mesmo tempo (duas pessoas lendo o mesmo livro), e cada um está numa página.
| Peça | No livro | No Python |
|---|---|---|
| Iterável | O livro | Lista, tupla, texto, dicionário, conjunto, arquivo, range… |
iter(coisa) | "Me dá um marcador para este livro" | Cria um iterador novo, parado antes do primeiro item |
next(iterador) | "Vira a página" | Entrega o próximo item e avança |
StopIteration | "O livro acabou" | A exceção que next() lança quando não há mais itens |
1. iter() e next() no modo interativo
Abra o modo interativo (aula O Modo Interativo) e acompanhe. Primeiro a lista; depois, o iterador dela; depois, um next() de cada vez:
$ python3
Python 3.14.4 (main, Aug 20 2026, 10:41:58) [GCC 15.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> numeros = [10, 20, 30]
>>> it = iter(numeros)
>>> next(it)
10
>>> next(it)
20
>>> next(it)
30
>>> next(it)
Traceback (most recent call last):
File "<python-input-5>", line 1, in <module>
next(it)
~~~~^^^^
StopIteration
>>> exit()
- numeros = [10, 20, 30]
- O iterável: a lista com os três números.
- it = iter(numeros)
iter()pede à lista um iterador novo. O iterador fica parado antes do primeiro item. O nomeité só um costume curto para "iterador".- next(it)
- "Próximo": entrega o item da vez e anda uma casa. Três
next(), três números, na ordem. - o quarto next(it)
- Não há mais itens. O iterador avisa lançando a exceção
StopIteration("parar a iteração").
Lendo o traceback
É o primeiro traceback desta aula, então vamos linha por linha:
Traceback (most recent call last):"rastro (a chamada mais recente por último)": o Python vai mostrar o caminho até o erro.File "<python-input-5>", line 1, in <module>: o erro aconteceu na entrada número 5 do modo interativo (ele conta a partir de 0), linha 1, no programa principal.next(it)com~~~~^^^^embaixo: o Python 3.14 sublinha a parte culpada; os^apontam o(it), a chamada que falhou.StopIteration: o nome da exceção. Repare que ela não traz mensagem nenhuma depois do nome: não há nada para explicar, o iterador simplesmente acabou.
StopIteration não é um defeito
Ao contrário de um NameError ou de um TypeError, o StopIteration é um aviso combinado: é o jeito que todo iterador do Python tem de dizer "acabou". Você só o vê assim, em vermelho, porque chamou next() na mão e ninguém estava esperando o aviso. O for espera por ele, e por isso você nunca o viu nos seus laços.
Missão: na padaria do bairro, o painel chama as senhas uma por vez. O programa já chama a primeira. Acrescente mais duas linhas com next(fila) para chamar a 102 e a 103.
senhas = [101, 102, 103, 104]
fila = iter(senhas)
print("Chamando a senha", next(fila))
senhas = [101, 102, 103, 104]
fila = iter(senhas)
print("Chamando a senha", next(fila))
print("Chamando a senha", next(fila))
print("Chamando a senha", next(fila))
print("Ainda na fila:", list(fila))
Na solução, a última linha mostra Ainda na fila: [104]: o list(fila) pegou só o que sobrou no iterador. O marcador já estava na senha 104.
2. next() com um valor padrão
Se você não quer o StopIteration, passe um segundo argumento ao next(): o valor que ele deve devolver quando acabar. No lugar do erro, vem esse valor, quantas vezes você pedir:
>>> compras = ["pão", "leite"] >>> it = iter(compras) >>> type(compras) <class 'list'> >>> type(it) <class 'list_iterator'> >>> next(it, "acabou") 'pão' >>> next(it, "acabou") 'leite' >>> next(it, "acabou") 'acabou' >>> next(it, "acabou") 'acabou'
Repare também no type(): a lista é uma list, e o iterador dela é outra coisa, um list_iterator ("iterador de lista"). São dois objetos diferentes: o livro e o marcador.
Todo iterável tem o seu iterador
Textos e dicionários funcionam igual. O iterador de um texto entrega uma letra por vez; o de um dicionário entrega as chaves (é por isso que for chave in dicionario: percorre as chaves, como na aula Percorrendo um Dicionário):
>>> letras = iter("café")
>>> next(letras)
'c'
>>> next(letras)
'a'
>>> precos = {"pão": 0.75, "leite": 5.49}
>>> chaves = iter(precos)
>>> next(chaves)
'pão'
>>> next(chaves)
'leite'
3. O for por dentro
Agora dá para entender o for. Os dois laços abaixo fazem exatamente a mesma coisa; o segundo é o que o Python faz, escondido, quando você escreve o primeiro:
compras = ["pão", "leite", "café"]
# 1. O jeito de sempre: o for
for item in compras:
print("Comprar:", item)
print("---")
# 2. O que o for faz por dentro
it = iter(compras)
while True:
try:
item = next(it)
except StopIteration:
break
print("Comprar:", item)
$ python3 por_dentro.py Comprar: pão Comprar: leite Comprar: café --- Comprar: pão Comprar: leite Comprar: café
it = iter(compras): antes da primeira volta, oforpede um iterador à lista.while True:repete "para sempre" (aula while)…item = next(it): …pedindo o próximo item e guardando na variável do laço.except StopIteration: break: quando o iterador avisa que acabou, otry(aula try e except) captura o aviso e obreaksai do laço. Sem traceback nenhum.print("Comprar:", item): o corpo dofor, uma vez por item.
É por isso que o mesmo for serve para listas, textos, dicionários, arquivos e range: ele não conhece nenhum deles. Ele só sabe pedir iter() uma vez e next() até vir o StopIteration. Quem souber responder a essas duas perguntas pode ir num for.
4. O iterador se gasta
O marcador de página só anda para a frente. Quando chega ao fim, fica lá. Veja o que acontece ao percorrer o mesmo iterador duas vezes:
senhas = iter([1, 2, 3])
print("Primeira volta:")
for s in senhas:
print(" senha", s)
print("Segunda volta:")
for s in senhas:
print(" senha", s)
print("Fim.")
$ python3 gasta.py Primeira volta: senha 1 senha 2 senha 3 Segunda volta: Fim.
A segunda volta não mostrou nada, e também não deu erro. O segundo for pediu iter(senhas), e o iterador de um iterador é ele mesmo, já no fim. O primeiro next() já veio com StopIteration, e o laço acabou sem nenhuma volta.
Agora o mesmo programa com a lista, sem o iter() na primeira linha (senhas = [1, 2, 3]):
$ python3 gasta_lista.py Primeira volta: senha 1 senha 2 senha 3 Segunda volta: senha 1 senha 2 senha 3
Com a lista, cada for pede um iterador novo, que começa do zero: um marcador novo para o mesmo livro. O modo interativo confirma a diferença com o operador is (aula is e in):
>>> it = iter([1, 2, 3]) >>> iter(it) is it True « o iterador de um iterador é ele mesmo >>> lista = [1, 2, 3] >>> iter(lista) is lista False « a lista entrega um objeto novo
Várias funções que você já usou devolvem iteradores, e não listas: map() e filter() (aula map() e filter()), zip() e enumerate() (aula enumerate() e zip()), e o arquivo aberto com open(). Todos se gastam na primeira passada.
precos = [4.50, 12.00, 7.25] print(sum(iter(precos))) print(max(iter(precos))) print(list(iter(precos))) print(sorted(iter(precos))) com_desconto = map(lambda p: p * 0.9, precos) print(com_desconto) print(list(com_desconto)) print(list(com_desconto))
$ python3 consumir.py 23.75 12.0 [4.5, 12.0, 7.25] [4.5, 7.25, 12.0] <map object at 0x7fa91a19b640> « o endereço muda a cada execução [4.05, 10.8, 6.525] []
sum(),max(),list()esorted()aceitam qualquer iterável, inclusive um iterador: eles fazem o próprio laço, comnext()até o fim.print(com_desconto)não mostra os preços: mostra o objetomap, que ainda não calculou nada. Os valores só são calculados quando alguém pede, um por um.- O primeiro
list(com_desconto)pede todos e gasta o iterador. O segundo recebe uma lista vazia,[]. (O6.525e o10.8são os preços com 10% de desconto; para mostrar com duas casas, use as f-strings.)
Se você precisa dos valores mais de uma vez, guarde numa lista logo de cara: com_desconto = list(map(…)).
O arquivo também é um iterador
Um arquivo aberto (aula Lendo Arquivos) entrega uma linha a cada next(). Dá para tirar a primeira linha na mão e deixar o resto para o for, um truque comum para pular o cabeçalho de um arquivo:
pão leite café
with open("compras.txt", encoding="utf-8") as arquivo:
print(type(arquivo))
primeira = next(arquivo)
print("Primeira linha:", primeira.strip())
for linha in arquivo:
print("Resto:", linha.strip())
$ python3 ler_arquivo.py <class '_io.TextIOWrapper'> Primeira linha: pão Resto: leite Resto: café
O for continuou de onde o next() parou: o arquivo é o próprio marcador. O .strip() tira a quebra de linha (\n) que vem no fim de cada linha.
Missão: o arquivo notas.csv tem um cabeçalho na primeira linha. Use next(arquivo) para ler o cabeçalho separado e mostrá-lo como Primeira linha: …; o for deve mostrar só os alunos.
with open("notas.csv", encoding="utf-8") as arquivo:
for linha in arquivo:
print("Aluno:", linha.strip())
nome,nota Ana,9.5 Bruno,7.0 Carla,8.5
with open("notas.csv", encoding="utf-8") as arquivo:
cabecalho = next(arquivo)
print("Primeira linha:", cabecalho.strip())
for linha in arquivo:
print("Aluno:", linha.strip())
5. Criando o seu iterador: __iter__ e __next__
O for só faz duas perguntas: iter() e next(). Por baixo, elas chamam dois métodos especiais do objeto (aula Métodos Especiais): iter(x) chama x.__iter__(), e next(x) chama x.__next__(). Escreva os dois numa classe (aula Classes e Objetos) e os objetos dela vão poder entrar num for.
A Ana quer uma contagem regressiva para a virada do ano:
class ContagemRegressiva:
def __init__(self, inicio):
self.atual = inicio
def __iter__(self):
return self
def __next__(self):
if self.atual <= 0:
raise StopIteration
valor = self.atual
self.atual -= 1
return valor
for numero in ContagemRegressiva(3):
print(numero)
print("Já!")
$ python3 contagem.py 3 2 1 Já!
- def __init__(self, inicio):
- Guarda em
self.atualo número de onde a contagem parte. É a "memória" do marcador: onde ele está agora. - def __iter__(self): return self
- A resposta para
iter(). Este objeto já é o marcador, então devolve a si mesmo. Todo iterador faz assim. - def __next__(self):
- A resposta para
next(): entrega o próximo item. - if self.atual <= 0: raise StopIteration
- Chegou ao fim? Então lança o aviso combinado com
raise(aula raise). Sem esta linha, a contagem nunca acaba (veja em Quando dá errado). - valor = self.atual / self.atual -= 1 / return valor
- Guarda o número da vez, anda uma casa e devolve o número guardado. A ordem importa: se você diminuísse antes de guardar, a contagem começaria do 2.
Chamando next() na mão, o StopIteration aparece com o caminho completo. Agora o traceback tem dois trechos: a linha do seu programa que chamou o next() e, embaixo, a linha do __next__ que lançou a exceção:
class ContagemRegressiva:
def __init__(self, inicio):
self.atual = inicio
def __iter__(self):
return self
def __next__(self):
if self.atual <= 0:
raise StopIteration
valor = self.atual
self.atual -= 1
return valor
c = ContagemRegressiva(2)
print(next(c))
print(next(c))
print(next(c))
$ python3 contagem_next.py
2
1
Traceback (most recent call last):
File "/home/ana/contagem_next.py", line 19, in <module>
print(next(c))
~~~~^^^
File "/home/ana/contagem_next.py", line 10, in __next__
raise StopIteration
StopIteration
Leia de cima para baixo: na linha 19, o terceiro print(next(c)) chamou o next(); ele foi parar no __next__, que, na linha 10, lançou o StopIteration. A chamada mais recente fica por último, como diz a primeira linha.
6. Iterável que pode ser percorrido várias vezes
A ContagemRegressiva é um iterador, e iteradores se gastam: um segundo for no mesmo objeto não mostraria nada. Uma lista não tem esse problema porque ela é um iterável, não um iterador: a cada iter(), ela fabrica um marcador novo. Dá para fazer o mesmo com duas classes, o livro e o marcador:
class Playlist:
def __init__(self, musicas):
self.musicas = musicas
def __iter__(self):
return PlaylistIterador(self.musicas)
class PlaylistIterador:
def __init__(self, musicas):
self.musicas = musicas
self.posicao = 0
def __iter__(self):
return self
def __next__(self):
if self.posicao >= len(self.musicas):
raise StopIteration
musica = self.musicas[self.posicao]
self.posicao += 1
return musica
festa = Playlist(["Asa Branca", "Garota de Ipanema", "Aquarela"])
for musica in festa:
print("Tocando:", musica)
print("De novo, desde o começo:")
for musica in festa:
print("Tocando:", musica)
$ python3 playlist.py Tocando: Asa Branca Tocando: Garota de Ipanema Tocando: Aquarela De novo, desde o começo: Tocando: Asa Branca Tocando: Garota de Ipanema Tocando: Aquarela
- class Playlist
- O iterável (o livro). Não tem
__next__: o__iter__dele fabrica um marcador novo a cada chamada. - class PlaylistIterador
- O iterador (o marcador). Guarda a
posicaoe tem o__next__. - self.posicao >= len(self.musicas)
- Passou da última música?
StopIteration.
Cada for chamou festa.__iter__(), ganhou um PlaylistIterador com posicao = 0 e tocou tudo desde o começo.
Formas diferentes de fazer um objeto percorrível
Quando os itens já estão guardados numa lista, você não precisa escrever o marcador: o __iter__ pode simplesmente devolver o iterador da própria lista.
class Playlist:
def __init__(self, musicas):
self.musicas = musicas
def __iter__(self):
return iter(self.musicas)
festa = Playlist(["Asa Branca", "Garota de Ipanema", "Aquarela"])
print(list(festa))
print(list(festa))
print("Aquarela" in festa)
$ python3 playlist_curta.py ['Asa Branca', 'Garota de Ipanema', 'Aquarela'] ['Asa Branca', 'Garota de Ipanema', 'Aquarela'] True
Funciona com list(), com for e até com in: o in também percorre o iterável, item por item, até achar. A terceira forma, a mais usada no dia a dia, é a função geradora, com yield, da próxima aula, Geradores: ela escreve o __iter__ e o __next__ para você.
| Forma | Quando usar |
|---|---|
__iter__ devolvendo iter(self.lista) | Os itens já estão numa lista (ou tupla, dicionário) dentro do objeto. A mais curta |
Classe com __iter__ e __next__ | Para entender como tudo funciona, ou quando o marcador precisa de uma lógica própria (uma contagem, uma leitura aos pedaços) |
| Duas classes: iterável + iterador | Quando o objeto precisa ser percorrido várias vezes, ou por dois laços ao mesmo tempo |
Função geradora com yield | Quase sempre, na prática: faz o mesmo que a classe com bem menos linhas (aula Geradores) |
Quando dá errado
next() direto na lista
compras = ["pão", "leite", "café"] print(next(compras))
$ python3 next_lista.py
Traceback (most recent call last):
File "/home/ana/next_lista.py", line 2, in <module>
print(next(compras))
~~~~^^^^^^^^^
TypeError: 'list' object is not an iterator
TypeError: 'list' object is not an iterator: "um objeto lista não é um iterador". A lista é o livro, não o marcador: ela não sabe qual é o "próximo". O ~~~~^^^^^^^^^ aponta a chamada next(compras) na linha 2. Como consertar: peça o iterador antes, it = iter(compras), e chame next(it).
__iter__ no for
A ContagemRegressiva com o __next__ certinho, mas sem o __iter__:
$ python3 sem_iter.py
Traceback (most recent call last):
File "/home/ana/sem_iter.py", line 13, in <module>
for numero in ContagemRegressiva(3):
~~~~~~~~~~~~~~~~~~^^^
TypeError: 'ContagemRegressiva' object is not iterable
"O objeto ContagemRegressiva não é iterável". Antes da primeira volta, o for chama iter(), e o objeto não sabe responder: falta o __iter__. Ter o __next__ não basta. Como consertar: acrescente def __iter__(self): return self.
__next__
O contrário: o __iter__ devolve self, mas a classe não tem __next__. É o código inicial da missão final:
$ python3 pares_ini.py
Traceback (most recent call last):
File "/home/ana/pares_ini.py", line 12, in <module>
print(list(Pares(10)))
~~~~^^^^^^^^^^^
TypeError: iter() returned non-iterator of type 'Pares'
"iter() devolveu um não-iterador, do tipo Pares". O __iter__ prometeu um marcador e entregou um objeto que não sabe fazer next(). Como consertar: escreva o __next__.
StopIteration: o laço que nunca acaba
Tire da ContagemRegressiva as duas linhas do if self.atual <= 0: raise StopIteration e rode no terminal:
$ python3 infinito.py
3
2
1
0
-1
-2
«… mais de 266 mil linhas, em um segundo …»
-266641
-266642
^C-266643
Traceback (most recent call last):
File "/home/ana/infinito.py", line 15, in <module>
print(numero)
~~~~~^^^^^^^^
KeyboardInterrupt
Não há erro nenhum no código, do ponto de vista do Python: o __next__ sempre tem um número para entregar, então o for nunca recebe o aviso de fim. A contagem passa do zero e segue pelos negativos até alguém apertar Ctrl+C. O terminal mostra o ^C na hora em que a tecla é apertada, por isso ele aparece colado no último número, que o Python ainda terminou de escrever. O Ctrl+C interrompe o programa com KeyboardInterrupt ("interrupção pelo teclado"). A linha que aparece no traceback é a que estava rodando no instante do Ctrl+C, e pode ser outra no seu terminal. Como consertar: todo __next__ precisa de um caminho que termine em raise StopIteration. (No editor do guia, um laço assim é parado pelo botão ■ Parar, ou sozinho depois de 10 segundos, sem o traceback do KeyboardInterrupt.)
in gastou o iterador (sem erro nenhum)
compras = iter(["pão", "leite", "café", "açúcar"])
if "leite" in compras:
print("Tem leite na lista!")
print("A lista inteira:")
for item in compras:
print(" ", item)
$ python3 in_gasta.py Tem leite na lista! A lista inteira: café açúcar
Sumiram o pão e o leite! Para responder ao in, o Python chamou next() até achar o "leite" e parou ali. O for continuou de onde o marcador ficou. É um erro de lógica: o programa roda, mas a resposta está errada. Como consertar: use a lista (sem o iter()), ou guarde uma lista com list(…) se o que você recebeu é um iterador.
Referência rápida
| Escrita | O que faz |
|---|---|
iter(x) | Pede um iterador para o iterável x (chama x.__iter__()) |
next(it) | O próximo item; StopIteration quando acabar (chama it.__next__()) |
next(it, padrao) | O próximo item; padrao quando acabar, sem exceção |
raise StopIteration | Dentro do __next__: avisa que não há mais itens |
def __iter__(self): return self | O que todo iterador escreve |
def __iter__(self): return iter(self.lista) | Objeto percorrível que repassa o iterador de uma lista |
list(it), sum(it), max(it), sorted(it) | Percorrem até o fim (e gastam o iterador) |
map, filter, zip, enumerate, arquivo aberto | Já são iteradores: servem para uma passada só |
| Sintoma | Causa provável |
|---|---|
StopIteration no seu programa | next() chamado na mão depois do fim; use next(it, padrao) ou um for |
TypeError: 'list' object is not an iterator | next() numa lista: falta o iter() |
TypeError: 'X' object is not iterable | A classe não tem __iter__ |
TypeError: iter() returned non-iterator of type 'X' | O __iter__ devolve um objeto sem __next__ |
| O laço nunca acaba | O __next__ não tem um raise StopIteration |
O segundo for não mostra nada; itens "somem" | O iterador já foi gasto (por outro for, um list(), um in) |
Exercícios
1. Pedindo o marcador
Complete para mostrar 'pão':
it =
print()
2. Sem exceção no fim
O iterador it já acabou. Complete para que a chamada devolva o texto "fim" em vez de lançar StopIteration:
3. O nome do método
Qual método especial o next() chama no objeto? Escreva só o nome, com os sublinhados.
4. it = iter([1, 2]), depois print(list(it)) e print(list(it)). O que aparece?
5. Por que o for nunca mostra o StopIteration?
6. Qual destes é um iterador (e não só um iterável)?
Missão final: os números pares
Missão: a classe Pares deve entregar os números pares de 0 até o limite (incluindo o limite). Ela já tem o __init__ e o __iter__; rode e veja o erro. Depois escreva o __next__: se self.atual passou do limite, raise StopIteration; senão, guarde o valor, some 2 ao self.atual e devolva o valor guardado.
class Pares:
def __init__(self, limite):
self.limite = limite
self.atual = 0
def __iter__(self):
return self
# escreva aqui o __next__
print(list(Pares(10)))
class Pares:
def __init__(self, limite):
self.limite = limite
self.atual = 0
def __iter__(self):
return self
def __next__(self):
if self.atual > self.limite:
raise StopIteration
valor = self.atual
self.atual += 2
return valor
print(list(Pares(10)))
Com o __next__ no lugar, sai [0, 2, 4, 6, 8, 10]. Experimente trocar o list(Pares(10)) por um for e por sum(Pares(10)): o mesmo objeto serve para tudo que percorre.
Resumo
- Iterável é o que dá para percorrer (o livro); iterador é quem percorre e lembra onde parou (o marcador).
iter(x)pede um iterador;next(it)entrega o próximo item; no fim, vem oStopIteration, ou o valor padrão denext(it, padrao).- O
foré umiter()seguido denext()até oStopIteration, que ele captura em silêncio. - Um iterador se gasta: só anda para a frente. Listas não se gastam porque cada
forpede um iterador novo.map,filter,zip,enumeratee arquivos são iteradores. - Para criar o seu:
__iter__devolveself;__next__entrega o próximo ou lançaStopIteration. Sem oraise, o laço nunca acaba. - Na próxima aula, Geradores, o
yieldfaz tudo isso com muito menos código.