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.

Você vai aprender
  • 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 com next().
  • O que é o StopIteration e por que você quase nunca o vê.
  • O que o for faz 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-iterator e 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çaNo livroNo Python
IterávelO livroLista, 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 nome it é 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é
  1. it = iter(compras): antes da primeira volta, o for pede um iterador à lista.
  2. while True: repete "para sempre" (aula while)…
  3. item = next(it): …pedindo o próximo item e guardando na variável do laço.
  4. except StopIteration: break: quando o iterador avisa que acabou, o try (aula try e except) captura o aviso e o break sai do laço. Sem traceback nenhum.
  5. print("Comprar:", item): o corpo do for, 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
Quem devolve iteradores (e se gasta)

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() e sorted() aceitam qualquer iterável, inclusive um iterador: eles fazem o próprio laço, com next() até o fim.
  • print(com_desconto) não mostra os preços: mostra o objeto map, 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, []. (O 6.525 e o 10.8 sã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.atual o 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 posicao e 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ê.

FormaQuando 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 + iteradorQuando o objeto precisa ser percorrido várias vezes, ou por dois laços ao mesmo tempo
Função geradora com yieldQuase 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).

Classe sem __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.

Classe sem __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__.

Esqueceu o 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.)

O 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

EscritaO 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 StopIterationDentro do __next__: avisa que não há mais itens
def __iter__(self): return selfO 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 abertoJá são iteradores: servem para uma passada só
SintomaCausa provável
StopIteration no seu programanext() chamado na mão depois do fim; use next(it, padrao) ou um for
TypeError: 'list' object is not an iteratornext() numa lista: falta o iter()
TypeError: 'X' object is not iterableA classe não tem __iter__
TypeError: iter() returned non-iterator of type 'X'O __iter__ devolve um objeto sem __next__
O laço nunca acabaO __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':

compras = ["pão", "leite"]
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:

next(it, )

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 o StopIteration, ou o valor padrão de next(it, padrao).
  • O for é um iter() seguido de next() até o StopIteration, que ele captura em silêncio.
  • Um iterador se gasta: só anda para a frente. Listas não se gastam porque cada for pede um iterador novo. map, filter, zip, enumerate e arquivos são iteradores.
  • Para criar o seu: __iter__ devolve self; __next__ entrega o próximo ou lança StopIteration. Sem o raise, o laço nunca acaba.
  • Na próxima aula, Geradores, o yield faz tudo isso com muito menos código.