
Passo 1 de 7
Entregar o objeto ou seus elementos
Compare yield e yield from aplicados à mesma coleção.
Trilha de aprendizado · Nível 10 · Tutorial 5
Decompor uma função geradora em partes menores e encaminhar os elementos produzidos por outros iteráveis usando yield from.
Entregar o objeto ou seus elementos
Compare yield e yield from aplicados à mesma coleção. 1 min
Substituir o encaminhamento simples
Reconheça quando um laço apenas repassa valores e simplifique-o com yield from, preservando a sequência produzida. 2 min
Acompanhar a delegação e a retomada
Preveja como o controle passa do consumidor para o gerador externo, para a fonte delegada e de volta ao código externo. 2 min
Distribuir a produção entre subgeradores
Divida a produção em funções geradoras auxiliares e coordene a sequência completa com yield from. 2 min
Achatar somente o nível desejado
Use um laço externo com yield from para encaminhar os elementos de cada fonte interna, preservando os níveis mais profundos. 2 min
Respeitar o estado de cada fonte
Veja como fontes vazias, esgotadas e parcialmente consumidas determinam o que uma delegação com yield from ainda pode produzir. 2 min
Aplicação final: refatorar e verificar
Refatore uma produção em lotes com subgeradores e confirme localmente a ordem, a continuação e o respeito ao estado das fontes. 2 min

Passo 1 de 7
Compare yield e yield from aplicados à mesma coleção.
Considere a lista ["maçã", "pera", "uva"]. Com yield, a lista inteira é um único valor produzido. Com yield from, o gerador delega a produção para a lista e entrega cada elemento dela separadamente.
A mesma lista pode sair inteira em um avanço ou ter seus itens entregues em avanços sucessivos.

yield frutas produz um objeto lista; yield from frutas produz os elementos da lista.
Execute cada função e observe o resultado de list(...).
def com_yield():
frutas = ["maçã", "pera", "uva"]
yield frutas
print(list(com_yield()))
# [['maçã', 'pera', 'uva']]A fonte delegada continua sendo a mesma lista.
def com_yield_from():
frutas = ["maçã", "pera", "uva"]
yield from frutas
print(list(com_yield_from()))
# ['maçã', 'pera', 'uva']Dica
No primeiro resultado, há uma lista dentro da lista externa criada por list(...): foi produzido um único valor, que por sua vez é uma lista. No segundo, os três textos foram produzidos individualmente.
Considere:
<code>def pacote():
yield [10, 20]
def itens():
yield from [10, 20]
print(next(pacote()))
print(list(itens()))</code>
Quais valores são exibidos, nessa ordem?

Passo 2 de 7
Reconheça quando um laço apenas repassa valores e simplifique-o com yield from, preservando a sequência produzida.
Quando um gerador percorre uma fonte e entrega cada elemento sem modificá-lo, o laço for pode ser substituído por yield from. Nos dois casos, o consumidor recebe os mesmos valores, na mesma ordem, ao usar next() ou for.
def encaminhar_com_for(fonte):
for item in fonte:
yield item
def encaminhar_com_yield_from(fonte):
yield from fonte
print(list(encaminhar_com_for(["a", "b", "c"])))
print(list(encaminhar_com_yield_from(["a", "b", "c"])))
# Ambas produzem: ['a', 'b', 'c']
yield from fonte substitui o encaminhamento simples feito por for item in fonte: yield item.
yield from aceita uma coleção, um iterador ou outro objeto gerador. A delegação começa no estado atual da fonte: se você passar um iterador que já avançou, apenas os elementos restantes serão encaminhados.
def encaminhar(fonte):
yield from fonte
numeros = [1, 2, 3] # coleção
itens = iter([10, 20, 30]) # iterador
next(itens) # consome 10
quadrados = (n * n for n in [2, 3]) # objeto gerador
print(list(encaminhar(numeros))) # [1, 2, 3]
print(list(encaminhar(itens))) # [20, 30]
print(list(encaminhar(quadrados))) # [4, 9]Dica
Faça a substituição somente se o corpo do laço for, na prática, apenas yield item. A forma curta comunica que este gerador não altera os elementos: ele só delega sua produção.
Complete o corpo para substituir o laço por delegação:
def registros_ativos(registros):
____ registrosA função deve produzir os mesmos valores que for registro in registros: yield registro.
Não remova o laço se ele transforma, filtra ou executa uma ação para cada elemento. Nesses casos, o corpo faz trabalho próprio antes de entregar algo; yield from fonte entregaria os valores originais sem esse trabalho.
def dobrar(numeros):
for numero in numeros:
yield numero * 2
print(list(dobrar([1, 2, 3])))
# [2, 4, 6]
# yield from numeros NÃO seria equivalente:
# produziria [1, 2, 3], sem dobrar os valores.Em qual função a substituição direta por yield from fonte preserva os valores produzidos?

Passo 3 de 7
Preveja como o controle passa do consumidor para o gerador externo, para a fonte delegada e de volta ao código externo.
Considere um gerador externo que entrega um valor inicial, delega dois valores e depois entrega um valor final. Enquanto a fonte delegada ainda tem elementos, cada next() do consumidor recebe um elemento dela. O código após yield from permanece suspenso.
def sequencia():
yield "início"
yield from ["A", "B"]
yield "fim"
fluxo = sequencia()
print(next(fluxo)) # início
print(next(fluxo)) # A
print(next(fluxo)) # B
print(next(fluxo)) # fim
A delegação encaminha a demanda do consumidor à fonte, elemento por elemento.
Na terceira chamada, next(fluxo) entrega "B", o último elemento da lista. Nesse momento, o consumidor ainda recebeu um valor da fonte delegada. Somente na chamada seguinte Python tenta avançar a fonte novamente, detecta seu esgotamento e retoma o código logo após yield from; por isso essa quarta chamada produz "fim".
Dica
Pense em yield from fonte como: “continue pedindo o próximo valor à fonte”. O trecho posterior só pode executar quando uma nova tentativa de avanço percebe que a fonte acabou.”
Usando a função sequencia() mostrada, coloque os eventos na ordem em que ocorrem ao chamar next(fluxo) quatro vezes.

Passo 4 de 7
Divida a produção em funções geradoras auxiliares e coordene a sequência completa com yield from.
Uma função auxiliar pode produzir apenas um trecho da sequência. Ao chamá-la, você obtém um objeto gerador: esse é o subgerador.
A função externa coordena os trechos. Ela não precisa repetir a lógica de cada produção: delega a cada subgerador com yield from.
Observe que a coordenação passa integralmente pelo primeiro subgerador antes de iniciar o segundo.

Cada subgerador termina antes de a delegação seguinte começar.
Cada chamada, como cabecalho(), fornece o subgerador usado pela delegação.
def cabecalho():
yield "início"
yield "itens"
def rodape():
yield "fim"
def relatorio():
yield from cabecalho()
yield from rodape()
print(list(relatorio()))
# ['início', 'itens', 'fim']relatorio() delega a cabecalho() até ela se esgotar. Só então alcança yield from rodape().
Assim, os valores não se alternam automaticamente entre os subgeradores: a composição é sequencial.
Refatore esta produção em duas funções auxiliares e uma coordenadora, preservando exatamente a ordem produzida:
<code>def numeros():
yield 2
yield 4
yield 1
yield 3</code>
Uma auxiliar deve produzir 2 e 4; a outra, 1 e 3. A coordenadora deve usar yield from para reuni-las.
Escreva pelo menos 80 caracteres (0/80).

Passo 5 de 7
Use um laço externo com yield from para encaminhar os elementos de cada fonte interna, preservando os níveis mais profundos.
Quando uma coleção contém outras fontes, percorra primeiro a coleção externa. Em cada volta, use yield from na fonte interna atual.
Assim, o gerador entrega os elementos de cada fonte em sequência: termina uma fonte antes de começar a próxima.
O laço externo escolhe uma fonte interna por vez; yield from entrega os elementos dela.

A coleção externa organiza as fontes; a delegação produz os elementos de cada fonte.
Experimente no seu editor e observe o resultado de list(achatar_um_nivel(...)).
def achatar_um_nivel(fontes):
for fonte in fontes:
yield from fonte
lotes = [["A", "B"], ["C"], ["D", "E"]]
print(list(achatar_um_nivel(lotes)))
# ['A', 'B', 'C', 'D', 'E']Atenção
yield from fontes entrega cada fonte interna como um único elemento. Para entregar o conteúdo de cada fonte interna, o yield from precisa ficar dentro do for.
O laço percorre apenas as fontes no nível externo. Se uma delas contém outra lista, essa lista mais profunda é entregue como um único elemento — ela não é percorrida automaticamente.
A lista [2, 3] pertence à primeira fonte interna. Por isso, ela permanece agrupada na saída.
dados = [[1, [2, 3]], [4, 5]]
print(list(achatar_um_nivel(dados)))
# [1, [2, 3], 4, 5]Considere a função achatar_um_nivel e a chamada abaixo. Qual é a saída?
list(achatar_um_nivel([["a", ["b", "c"]], ["d"]]))

Passo 6 de 7
Veja como fontes vazias, esgotadas e parcialmente consumidas determinam o que uma delegação com yield from ainda pode produzir.
yield from fonte consome a fonte recebida exatamente como ela está. Se ela estiver vazia ou já esgotada, nenhum valor é entregue nessa etapa. Ainda assim, o gerador externo prossegue para as instruções seguintes.
A delegação consulta a fonte no estado em que ela foi recebida.

Fontes sem elementos não produzem nada, mas não impedem a continuação do gerador externo.
Execute este código e observe que as duas fontes não acrescentam valores, mas "fim" continua acessível.
def relatorio(fonte):
yield "início"
yield from fonte
yield "fim"
print(list(relatorio([])))
numeros = iter([10, 20])
list(numeros) # esgota o iterador
print(list(relatorio(numeros)))Exemplo
['início', 'fim']
['início', 'fim']Uma lista vazia já não tem elementos. O iterador numeros também não tem: ele foi consumido por list(numeros) antes de ser delegado.
Neste caso, next() já retirou o primeiro valor do iterador antes da chamada de sequencia.
def sequencia(fonte):
yield "antes"
yield from fonte
yield "depois"
itens = iter(["A", "B", "C"])
print(next(itens))
print(list(sequencia(itens)))Exemplo
A
['antes', 'B', 'C', 'depois']yield from itens não faz cópia e não volta para "A": delega somente os elementos restantes.
Dica
Ao delegar uma lista diretamente, cada nova chamada de sequencia(lista) obtém um novo percurso da lista. Ao reutilizar o mesmo iterador, a próxima chamada continua de onde o consumo anterior parou — ou não produz nada, se ele já estiver esgotado.
Considere o código:
fonte = iter([1, 2, 3])
next(fonte)
def produzir():
yield from fonte
list(produzir()) == [2, 3]A expressão final é verdadeira?

Passo 7 de 7
Refatore uma produção em lotes com subgeradores e confirme localmente a ordem, a continuação e o respeito ao estado das fontes.
Você vai transformar uma função que percorre lotes manualmente em uma versão composta por auxiliares. Cada auxiliar produz um trecho; a função coordenadora percorre os lotes e delega os elementos de cada um.
Use yield quando o resultado desejado for o próprio objeto composto. Use yield from quando quiser encaminhar os elementos da fonte.
A coordenação percorre os lotes externos; cada delegação esgota somente o lote atual antes de começar o próximo.

O lote vazio não produz valores, mas a coordenadora segue para o lote seguinte.
No seu computador, crie o arquivo test_lotes.py com o conteúdo abaixo. Primeiro, execute pytest -q: a implementação inicial deve falhar em um teste. Depois, substitua somente o corpo de produzir_lotes pela versão indicada no comentário e execute o comando novamente.
import pytest
def produzir_lote(lote):
yield from lote
def produzir_lotes(lotes):
# Versão inicial: entrega cada lote como um único objeto.
# Refatore este corpo para encaminhar os elementos de cada lote.
for lote in lotes:
yield lote
def com_marcadores(fonte):
yield "inicio"
yield from fonte
yield "fim"
def test_produzir_lotes_une_um_nivel_na_ordem():
lotes = [["A", "B"], [], ["C"]]
assert list(produzir_lotes(lotes)) == ["A", "B", "C"]
def test_continua_depois_de_fonte_vazia():
assert list(com_marcadores([])) == ["inicio", "fim"]
def test_iterador_parcial_comeca_na_posicao_atual():
numeros = iter([10, 20, 30])
assert next(numeros) == 10
assert list(produzir_lote(numeros)) == [20, 30]
# Substituição esperada para o corpo de produzir_lotes:
# for lote in lotes:
# yield from produzir_lote(lote)
Após executar os testes, explique: por que a fonte vazia ainda permite a produção de "fim"? E por que o iterador numeros não volta a entregar 10?
Escreva pelo menos 80 caracteres (0/80).
Resumo
Parabéns! Você concluiu: Delegar a produção de valores com yield from
Milhares de cursos online em vídeo, ebooks e áudiobooks.
Para testar seus conhecimentos no decorrer dos cursos online
Gerado diretamente na galeria de fotos do seu celular e enviado ao seu e-mail
Baixe nosso aplicativo pelo QR Code ou pelos links abaixo:.
+ de 10 milhões
de alunos
Certificado grátis e
válido em todo o Brasil
60 mil exercícios
gratuitos
4,8/5 classificação
nas lojas de apps
Cursos gratuitos em
vídeo, ebooks e audiobooks