Trilha de aprendizado · Nível 10 · Tutorial 6

Limitar o consumo de iteradores com itertools

Extrair trechos finitos e prefixos condicionais de iteradores, inclusive de fontes potencialmente infinitas, controlando quais elementos são consumidos.

  • Nível: Intermediário
  • Duração: 16 min
  • 7 passos
Limitar o consumo de iteradores com itertools

O que você vai percorrer

  1. Criar uma fonte sem término próprio com count Crie progressões numéricas sob demanda com itertools.count e reconheça por que elas precisam de um limite antes de serem consumidas por inteiro. 2 min
  2. Limitar a quantidade com islice Use itertools.islice para colocar um limite finito antes de consumir uma fonte, inclusive uma fonte criada por count. 2 min
  3. Selecionar posições com início, parada e passo Use início, parada e passo para selecionar posições de um iterador e acompanhe o avanço necessário da fonte. 3 min
  4. Rastrear o avanço da fonte em islice Visualize o que um recorte entrega, descarta e deixa disponível na fonte original. 3 min
  5. Extrair um prefixo com takewhile Use uma condição para obter apenas o começo contínuo de uma fonte, interrompendo na primeira falha. 2 min
  6. Identificar o elemento descartado na fronteira Entenda por que o primeiro valor que não atende ao predicado de takewhile também avança a fonte. 2 min
  7. Aplicar os limites e conferir o consumo Escolha entre islice e takewhile, preveja o avanço da fonte e confira o resultado no seu próprio Python. 3 min

O que você vai aprender

  • Criar uma fonte numérica potencialmente infinita com itertools.count.
  • Delimitar o consumo por posições usando itertools.islice.
  • Extrair um prefixo condicionado por uma função usando itertools.takewhile.
  • Prever quais elementos da fonte foram descartados ou permanecem disponíveis após cada operação.

Antes de começar

  • Consumir iteradores com iter e next
  • Passar funções como argumentos
  • Separar código em módulos e usar importações explícitas

Passo 1 de 7

Criar uma fonte sem término próprio com count

Crie progressões numéricas sob demanda com itertools.count e reconheça por que elas precisam de um limite antes de serem consumidas por inteiro.

Uma progressão sob demanda

Importe e crie

O módulo padrão itertools reúne operações que produzem ou recebem iteradores. Para usar count, importe-a explicitamente.

count(início, passo) produz números sob demanda. Ela não cria uma lista inteira: cada valor só é gerado quando alguém o solicita.

Fonte numérica sem fim próprio

python
from itertools import count

numeros = count(10, 3)

print(next(numeros))  # 10
print(next(numeros))  # 13
print(next(numeros))  # 16

Como count avança

Diagrama de uma fonte count iniciando em 10 e entregando 10, 13 e 16 em sequência, com uma seta contínua indicando que outros valores seguem disponíveis.

O início é 10; o passo 3 é a diferença entre valores consecutivos.

Início e passo não são um limite

Valores padrão e significado dos argumentos

Sem argumentos, count() começa em 0 e avança de 1 em 1. Assim, os primeiros valores são 0, 1, 2, 3, ....

O segundo argumento define o quanto o próximo valor aumenta ou diminui em relação ao anterior. Ele não informa quantos valores serão produzidos. Por exemplo, count(5, 2) segue com 5, 7, 9, 11, ..., sem um último valor próprio.

Atenção

Não esgote count diretamente

Evite usar list(count()) ou sum(count()). Como a fonte não termina sozinha, list continua acumulando valores e sum continua somando, sem conclusão normal. Nos próximos passos, você aprenderá a delimitar esse consumo antes dessas operações.

Preveja a próxima produção

Complete a sequência

Considere o código:

fonte = count(2, 4)
next(fonte) entrega 2 e a segunda chamada entrega 6.

A terceira chamada a next(fonte) entrega ____.

Passo 2 de 7

Limitar a quantidade com islice

Use itertools.islice para colocar um limite finito antes de consumir uma fonte, inclusive uma fonte criada por count.

Um limite antes do consumidor

Recorte de quantidade

Use islice(fonte, parada) para obter elementos da posição 0 até antes de parada. Assim como em uma fatia, a parada é exclusiva: islice(fonte, 5) pode entregar cinco elementos.

Como o limite atua

O recorte fica entre a fonte e quem vai consumir os valores.

Diagrama mostrando uma fonte numérica contínua, um recorte que deixa passar os cinco primeiros valores e uma lista finita como destino.

islice limita o que chega ao consumidor, sem precisar materializar a fonte inteira.

Dica

Criação não é consumo

islice(...) devolve outro iterador. Criá-lo não pede valores à fonte; o avanço acontece quando um consumidor, como list ou sum, solicita os elementos.

Lista finita a partir de count

Limite para list

Execute este exemplo no Python do seu computador.

python
from itertools import count, islice

numeros = count(10, 3)
primeiros_quatro = islice(numeros, 4)

print(list(primeiros_quatro))  # [10, 13, 16, 19]

Exemplo

Leitura do código

count(10, 3) não tem um fim próprio. Já islice(numeros, 4) entrega no máximo quatro valores: as posições 0, 1, 2 e 3. Por isso list(...) termina normalmente.

Limite para sum

Também é possível agregar apenas um trecho finito.

python
from itertools import count, islice

numeros = count(2, 2)
total = sum(islice(numeros, 5))

print(total)  # 30

Quando a fonte acaba ou o limite é zero

“No máximo” é importante

islice não inventa elementos. Se a fonte terminar antes da parada, ele entrega apenas os disponíveis. E islice(fonte, 0) é vazio: nenhum elemento é solicitado à fonte.

Fonte curta e limite zero

Compare os dois casos.

python
from itertools import islice

print(list(islice(iter([7, 8]), 5)))  # [7, 8]

fonte = iter([7, 8])
print(list(islice(fonte, 0)))         # []
print(next(fonte))                    # 7

Atenção

Evite consumir count sem limite

Não aplique list(count()) nem sum(count()) diretamente: essas operações esperam o esgotamento da fonte, mas count continua produzindo valores. Coloque um limite finito com islice antes delas.

Confira o limite

Escolha a expressão

Qual expressão produz a lista [1, 2, 3, 4, 5, 6] sem tentar esgotar count(1)?

Fonte menor que o recorte

Qual será o resultado de list(islice(iter([4, 9, 16]), 10))?

Passo 3 de 7

Selecionar posições com início, parada e passo

Use início, parada e passo para selecionar posições de um iterador e acompanhe o avanço necessário da fonte.

Quatro parâmetros, posições relativas

A forma completa de islice

Use islice(fonte, início, parada, passo) para selecionar posições do fluxo atual.

  • início é inclusivo: a primeira posição que pode ser entregue.
  • parada é exclusiva: essa posição não é entregue.
  • passo define o espaçamento entre as posições escolhidas.

Assim como em uma fatia, as posições começam em 0. Mas islice trabalha avançando um iterador: elas são relativas ao ponto em que a fonte está agora, não aos valores numéricos produzidos.

Posições não são valores

Neste exemplo, count(10, 10) produz valores de 10 em 10. islice(fonte, 2, 8, 3) escolhe as posições 2 e 5, entregando 30 e 60.

Diagrama de uma fonte count produzindo os valores 10, 20, 30, 40, 50, 60, 70 e 80, com as posições 2 e 5 destacadas como selecionadas; as demais posições anteriores à parada aparecem não selecionadas.

O passo 3 de islice pula posições; ele não altera o incremento de 10 usado por count.

Separando o passo da fonte do passo do recorte

Selecionar posições 2 e 5

Execute este exemplo no Python do seu computador.

python
from itertools import count, islice

fonte = count(10, 10)
recorte = islice(fonte, 2, 8, 3)

print(list(recorte))  # [30, 60]

O que acontece no fluxo

O count(10, 10) define os valores: 10, 20, 30, 40...

Já o último argumento de islice, 3, seleciona as posições 2, 5, 8... enquanto elas forem menores que 8. Portanto, ele escolhe posições 2 e 5; a posição 8 fica fora por causa da parada exclusiva.

Atenção

Não há índices nem retorno

Um iterador não oferece acesso aleatório como uma lista. Para chegar ao início e pular posições, islice avança a fonte e descarta os elementos não selecionados. Depois de avançar, não é possível voltar para buscá-los novamente.

Parâmetros aceitos

Limites para as posições

Quando início e parada são inteiros, ambos devem ser não negativos. O passo deve ser um inteiro positivo.

parada=None deixa de impor uma fronteira posicional finita. Em uma fonte como count, isso significa que uma operação consumidora como list(...) não terá término normal.

Uma seleção válida sem parada finita

Não execute list(recorte) neste caso: ele continuaria recebendo valores de count. Use next para observar apenas alguns.

python
from itertools import count, islice

fonte = count()
recorte = islice(fonte, 1, None, 2)

print(next(recorte))  # 1
print(next(recorte))  # 3
print(next(recorte))  # 5

Configuração válida

Qual chamada está configurada com parâmetros válidos para islice?

Aplique a seleção por posições

Complete os argumentos

Uma fonte está no começo e o diagrama indica que devem ser entregues as posições 1, 4 e 7, sem incluir a posição 10.

Complete apenas os argumentos após fonte:

islice(fonte, ___)

Resumo

Guarde esta regra

  • islice(fonte, início, parada, passo) seleciona posições a partir do estado atual da fonte.
  • Início é inclusivo; parada é exclusiva; passo é o espaçamento entre posições escolhidas.
  • O passo de islice não é o passo numérico de count.
  • Avançar e pular posições consome elementos da fonte; não há acesso aleatório ou retrocesso.
  • Use posições não negativas e passo positivo; parada=None não limita uma fonte infinita.

Passo 4 de 7

Rastrear o avanço da fonte em islice

Visualize o que um recorte entrega, descarta e deixa disponível na fonte original.

Três destinos para os valores

A fonte continua avançando

islice não copia a fonte. Ao consumir o recorte, alguns valores são entregues, outros são descartados para alcançar as posições pedidas, e os demais continuam disponíveis a partir da posição atual da fonte.

Para prever o próximo next(fonte), acompanhe todos os valores consumidos — não apenas os que apareceram no resultado.

Mapa de um recorte

No recorte islice(fonte, 2, 8, 3), as posições 2 e 5 são entregues. As demais posições necessárias para chegar ao limite são consumidas e descartadas.

Diagrama de uma fonte com posições de zero a oito: posições dois e cinco seguem para a saída como entregues; posições zero, um, três, quatro, seis e sete são descartadas; posição oito permanece disponível.

Entregar poucos valores não significa consumir poucos valores da fonte.

Consumo parcial não esgota o recorte

Uma entrega por vez

Execute no seu Python e observe o próximo valor da fonte após cada chamada.

python
from itertools import count, islice

fonte = count(10)
recorte = islice(fonte, 2, 8, 3)

print(next(recorte))  # 12, da posição 2
print(next(fonte))    # 13, da posição 3

Exemplo

Por que o próximo é 13?

Para entregar 12, o recorte consumiu 10 e 11 como descartes e entregou 12. Ele ainda não precisou procurar a próxima posição selecionada, então 13 permanece disponível.

Parar depois de um next(recorte) não esgota recorte: a próxima posição que ele tentaria entregar seria a posição 5 da fonte original.

Dica

Rastreio prático

Após cada operação, desenhe uma seta logo depois do último valor realmente consumido. Essa seta indica onde a próxima chamada à fonte começará.

Esgotar pode avançar além da última entrega

Consumo total do mesmo formato de recorte

Agora esgote o recorte antes de consultar a fonte.

python
from itertools import count, islice

fonte = count(10)
recorte = islice(fonte, 2, 8, 3)

print(list(recorte))  # [12, 15]
print(next(fonte))    # 18

O salto final também conta

Embora a última entrega seja 15 (posição 5), list(recorte) precisa verificar o recorte até a parada exclusiva, posição 8. Por isso, as posições 6 e 7 também são consumidas e descartadas. O próximo valor é 18, da posição 8.

Com início e parada inteiros, fonte suficiente e sem outro consumidor, esgotar islice(fonte, início, parada, passo) consome max(início, parada) elementos da fonte. O passo muda as entregas, mas não esse ponto final de consumo.

Preveja o estado da fonte

Associe cada ação ao próximo valor da fonte

Cada caso começa com uma fonte independente: fonte = count(0). Associe a ação ao valor retornado em seguida por next(fonte).

Toque em um item e depois no par correspondente.

Passo 5 de 7

Extrair um prefixo com takewhile

Use uma condição para obter apenas o começo contínuo de uma fonte, interrompendo na primeira falha.

Um prefixo guiado por condição

takewhile para no primeiro não

Use itertools.takewhile(predicado, fonte) quando quiser receber o prefixo contínuo cujos elementos atendem a uma condição.

Ele devolve um iterador. A cada elemento solicitado, aplica o predicado e o entrega apenas se o resultado for verdadeiro. Ao encontrar o primeiro resultado falso, o prefixo termina.

A primeira falha define a fronteira

A condição é verificada em ordem: depois da primeira falha, takewhile não continua procurando novos valores aceitos.

Diagrama de uma sequência com 2, 4 e 6 aceitos em verde, 9 como primeira falha em vermelho e 8 e 10 depois dela apagados, sem avaliação.

Com lambda n: n % 2 == 0, o resultado é 2, 4 e 6. O 9 encerra o prefixo; 8 e 10 não entram na busca.

O predicado só roda ao consumir

Crie e consuma o prefixo

A criação de aceitos ainda não chama o lambda. A avaliação ocorre quando list pede os elementos.

python
from itertools import count, takewhile

numeros = count(3, 3)  # 3, 6, 9, 12, ...
aceitos = takewhile(lambda n: n < 10, numeros)

print(list(aceitos))  # [3, 6, 9]

Exemplo

Por que não aparece 12?

Os valores 3, 6 e 9 satisfazem n < 10. Ao chegar a 12, o predicado resulta em False, então takewhile encerra a entrega. Não é um filtro de todos os valores: é um recorte do início da fonte.

Atenção

Condição verdadeira não é limite

Com uma fonte potencialmente infinita, list(takewhile(lambda n: n >= 0, count())) não termina: a condição continua verdadeira para todos os valores produzidos. Para materializar ou agregar, use uma condição que possa falhar ou combine o consumo com um limite finito apropriado.

Posição ou condição?

Escolha pela regra que você conhece

islice limita pelas posições: por exemplo, “quero os próximos 4 elementos”. Já takewhile limita pelos valores, mas somente enquanto a condição for verdadeira sem interrupções.

Se a condição falhar e voltar a ser verdadeira mais adiante, esses valores posteriores não fazem parte do prefixo.

Verifique o comportamento

list(takewhile(lambda n: n < 5, [1, 3, 7, 2, 4])) resulta em [1, 3].

Preveja o prefixo

Resultado de takewhile

Qual é o resultado de list(takewhile(lambda n: n % 5 != 0, [1, 2, 3, 5, 6, 7]))?

Passo 6 de 7

Identificar o elemento descartado na fronteira

Entenda por que o primeiro valor que não atende ao predicado de takewhile também avança a fonte.

A falha também consome um elemento

A fronteira é examinada

Ao consumir um takewhile até o fim, ele precisa testar cada valor para decidir se continua. Portanto, o primeiro valor para o qual o predicado resulta em False já foi retirado da fonte.

Esse valor de fronteira não entra no prefixo entregue e também não fica disponível para uma chamada posterior a next(fonte).

O destino do valor de fronteira

Observe o avanço da fonte quando a condição deixa de ser verdadeira.

Diagrama de uma fonte com os valores 2, 4, 6, 8 e 10. Os valores 2, 4 e 6 são entregues por takewhile; o 8 é testado e descartado; o 10 permanece como próximo valor da fonte.

Em takewhile(lambda n: n < 8, fonte), o 8 encerra o prefixo, mas é consumido para que a condição possa ser testada.

Prefixo e próximo valor

Execute este código e compare as três partes do resultado.

python
from itertools import count, takewhile

fonte = count(2, 2)  # 2, 4, 6, 8, 10, ...
prefixo = takewhile(lambda numero: numero < 8, fonte)

print(list(prefixo))
print(next(fonte))

Exemplo

Resultado esperado

A saída é:

[2, 4, 6]
10

O 8 foi avaliado, rejeitado e descartado. Assim, o próximo valor disponível é 10, não 8.

Casos que mudam a fronteira

Falha inicial, pausa e esgotamento

Três situações ajudam a rastrear a fonte com precisão:

  • Falha no primeiro valor: o prefixo é vazio, mas o primeiro valor já foi consumido e descartado.
  • Parada antes da falha: se você parar de consumir o takewhile antes de ele encontrar um valor rejeitado, nenhuma fronteira foi examinada ainda.
  • Fonte finita totalmente aceita: se a fonte acaba enquanto todos os valores satisfazem o predicado, não existe valor rejeitado para descartar.

Três verificações independentes

Cada bloco cria sua própria fonte para que um caso não interfira no outro.

python
from itertools import takewhile

# 1. O primeiro valor falha.
fonte_1 = iter([9, 10, 11])
prefixo_1 = takewhile(lambda numero: numero < 5, fonte_1)
print(list(prefixo_1))       # []
print(next(fonte_1))         # 10; o 9 foi descartado

# 2. O consumo para antes de alcançar a falha.
fonte_2 = iter([2, 4, 8, 10])
prefixo_2 = takewhile(lambda numero: numero < 8, fonte_2)
print(next(prefixo_2))       # 2
print(next(fonte_2))         # 4; o 8 ainda não foi examinado

# 3. A fonte termina sem falhas.
fonte_3 = iter([1, 2, 3])
prefixo_3 = takewhile(lambda numero: numero < 5, fonte_3)
print(list(prefixo_3))       # [1, 2, 3]
print(next(fonte_3, None))   # None; não houve valor rejeitado

Dica

Rastreamento confiável

Não conclua que a fonte está na fronteira só porque o prefixo terminou. Quando ele terminou por uma condição falsa, a fronteira foi consumida. Quando terminou por esgotamento da fonte, não há fronteira rejeitada.

Preveja o estado da fonte

Rastreie cada consumo

Analise sem executar primeiro:

from itertools import takewhile

fonte_a = iter([3, 5, 7, 9])
prefixo_a = takewhile(lambda numero: numero < 7, fonte_a)
print(list(prefixo_a))
print(next(fonte_a))

fonte_b = iter([3, 5, 7, 9])
prefixo_b = takewhile(lambda numero: numero < 7, fonte_b)
print(next(prefixo_b))
print(next(fonte_b))

Para cada caso, informe: qual foi o prefixo recebido, se houve valor descartado e qual valor a fonte fornece em seguida. Justifique pelo ponto em que o consumo parou.

Escreva pelo menos 120 caracteres (0/120).

Passo 7 de 7

Aplicar os limites e conferir o consumo

Escolha entre islice e takewhile, preveja o avanço da fonte e confira o resultado no seu próprio Python.

Escolha o limite pelo que você sabe

Duas formas de limitar

Use islice quando você conhece a quantidade ou as posições que quer alcançar. Use takewhile quando quer o prefixo inicial cujos valores obedecem a uma condição.

Nos dois casos, a fonte avança de verdade: antes de executar, preveja o que será entregue, o que será descartado e qual será o próximo valor disponível.

Resultado e avanço não são a mesma coisa

Compare os dois tipos de limite: os pontos apagados representam valores que a fonte já forneceu, mas que não aparecem no resultado.

Diagrama com dois fluxos numéricos. No fluxo superior, um seletor por posições entrega alguns pontos e mostra outros pontos saltados como descartados. No inferior, um seletor condicional entrega um prefixo e consome um ponto de fronteira rejeitado; há um ponto seguinte ainda disponível.

Em islice, os saltos consomem posições. Em takewhile, o primeiro valor que falha é consumido para detectar a fronteira.

Caso 1 — recorte por posições

Faça a previsão antes de rodar

No código a seguir, islice(fonte, 2, 7, 2) seleciona as posições 2, 4 e 6 a partir do ponto atual da fonte. Anote sua previsão para recorte e para o próximo valor de fonte. Depois execute o código no Python do seu computador.

Teste posicional com islice

python
from itertools import count, islice

fonte = count(10, 5)
recorte = list(islice(fonte, 2, 7, 2))

print("Recorte:", recorte)
print("Próximo da fonte:", next(fonte))

Confira o consumo de islice

Qual foi o recorte e qual valor ficou como próximo na fonte? Explique quais valores foram consumidos sem serem entregues.

Escreva pelo menos 50 caracteres (0/50).

Caso 2 — prefixo condicionado e fechamento

Agora limite pela condição

Aqui o término é garantido porque a progressão cresce de 4 em 4 e, em algum momento, deixará de ser menor que 20. Antes de executar, preveja o prefixo, o primeiro valor rejeitado e o próximo valor que continuará disponível.

Teste condicional com takewhile

python
from itertools import count, takewhile

fonte = count(3, 4)
prefixo = list(takewhile(lambda numero: numero < 20, fonte))

print("Prefixo:", prefixo)
print("Próximo da fonte:", next(fonte))

Relate a fronteira

O que foi exibido? Justifique por que o valor que falhou na condição não aparece nem como próximo valor da fonte.

Escreva pelo menos 50 caracteres (0/50).

Resumo

Checklist para limitar fontes

Use este checklist antes de materializar uma fonte potencialmente infinita.

  • Escolha islice para uma quantidade ou posições conhecidas; escolha takewhile para um prefixo condicionado.
  • Delimite count antes de usar consumidores que precisariam esgotar a fonte, como list ou sum.
  • Em islice, posições saltadas também são consumidas; o resultado não mostra todos os avanços.
  • Em takewhile, a primeira falha encerra o prefixo e esse elemento é descartado.
  • Confira o estado real da fonte com next(fonte) somente quando isso fizer parte da sua verificação.

Tutorial concluído

Parabéns! Você concluiu: Limitar o consumo de iteradores com itertools

Muito bem! Agora você sabe limitar fontes potencialmente infinitas e rastrear exatamente o que cada limitador consome.

Baixe o Aplicativo agora para ter acesso a + de 5000 cursos gratuitos, exercícios, certificado e muito conteúdo sem pagar nada!

  • Cursos online 100% gratuitos do início ao fim

    Milhares de cursos online em vídeo, ebooks e áudiobooks.

  • Mais de 60 mil exercícios gratuitos

    Para testar seus conhecimentos no decorrer dos cursos online

  • Certificado Digital gratuito válido em todo o Brasil

    Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail

Aplicativo Cursa na tela de ebook, na tela de curso em vídeo e na tela de exercícios do curso, mais o certificado de conclusão de curso