Qual é a diferença entre iteradores e geradores? Alguns exemplos de quando você usaria cada caso seriam úteis.
iterator
é um conceito mais geral: qualquer objeto cuja classe tenha um next
método ( __next__
no Python 3) e um __iter__
método que o faça return self
.
Todo gerador é um iterador, mas não vice-versa. Um gerador é criado chamando uma função que possui uma ou mais yield
expressões ( yield
instruções, no Python 2.5 e anteriores) e é um objeto que atende à definição de an do parágrafo anterior iterator
.
Você pode usar um iterador personalizado, em vez de um gerador, quando precisar de uma classe com um comportamento de manutenção de estado um tanto complexo ou desejar expor outros métodos além de next
(e __iter__
e __init__
). Na maioria das vezes, um gerador (às vezes, para necessidades suficientemente simples, uma expressão de gerador ) é suficiente e é mais simples de codificar porque a manutenção do estado (dentro de limites razoáveis) é basicamente "feita por você", pois o quadro é suspenso e retomado.
Por exemplo, um gerador como:
def squares(start, stop):
for i in range(start, stop):
yield i * i
generator = squares(a, b)
ou a expressão equivalente do gerador (genexp)
generator = (i*i for i in range(a, b))
levaria mais código para criar como um iterador personalizado:
class Squares(object):
def __init__(self, start, stop):
self.start = start
self.stop = stop
def __iter__(self): return self
def next(self): # __next__ in Python 3
if self.start >= self.stop:
raise StopIteration
current = self.start * self.start
self.start += 1
return current
iterator = Squares(a, b)
Mas, é claro, com a aula Squares
você poderia facilmente oferecer métodos extras, ou seja,
def current(self):
return self.start
se você tiver alguma necessidade real dessa funcionalidade extra em seu aplicativo.
for ... in ...:
, passado para uma função, ou você estará ligandoiter.next()
for..in
sintaxe. Talvez eu estivesse perdendo alguma coisa, mas isso foi há algum tempo atrás, não me lembro se resolvi. Obrigado!Em resumo: Iteradores são objetos que possuem um método
__iter__
e__next__
(next
no Python 2). Os geradores fornecem uma maneira fácil e integrada de criar instâncias de iteradores.Uma função com rendimento ainda é uma função que, quando chamada, retorna uma instância de um objeto gerador:
Uma expressão de gerador também retorna um gerador:
Para uma exposição e exemplos mais detalhados, continue lendo.
Um gerador é um iterador
Especificamente, o gerador é um subtipo de iterador.
Podemos criar um gerador de várias maneiras. Uma maneira muito comum e simples de fazer isso é com uma função.
Especificamente, uma função com rendimento nela é uma função que, quando chamada, retorna um gerador:
E um gerador, novamente, é um Iterador:
Um iterador é um iterável
Um iterador é um iterável,
que requer um
__iter__
método que retorna um iterador:Alguns exemplos de iteráveis são as tuplas, listas, dicionários, conjuntos, conjuntos congelados, cadeias, cadeias de bytes, matrizes de bytes, intervalos e visões de memória:
Iteradores requerem um
next
ou__next__
métodoNo Python 2:
E no Python 3:
Podemos obter os iteradores dos objetos internos (ou objetos personalizados) com a
iter
função:O
__iter__
método é chamado quando você tenta usar um objeto com um loop for. Em seguida, o__next__
método é chamado no objeto iterador para obter cada item do loop. O iterador aumentaStopIteration
quando você o esgotou e não pode ser reutilizado nesse ponto.A partir da documentação
Na seção Tipos de Gerador da seção Tipos de Iterador da documentação de Tipos Internos :
(Enfase adicionada.)
Portanto, aprendemos que os geradores são um tipo (conveniente) de iterador.
Objetos Iteradores de Exemplo
Você pode criar um objeto que implemente o protocolo Iterator criando ou estendendo seu próprio objeto.
Mas é mais fácil simplesmente usar um gerador para fazer isso:
Ou talvez mais simples, uma Expressão de Gerador (funciona de maneira semelhante à lista de compreensões):
Todos eles podem ser usados da mesma maneira:
Conclusão
Você pode usar o protocolo Iterator diretamente quando precisar estender um objeto Python como um objeto que pode ser iterado.
No entanto, na grande maioria dos casos, você é o mais indicado
yield
para definir uma função que retorna um iterador de gerador ou considera expressões de gerador.Por fim, observe que os geradores fornecem ainda mais funcionalidade como corotinas. Explico Generators, juntamente com a
yield
declaração, em profundidade na minha resposta para "O que a palavra-chave" yield "faz?".fonte
Iteradores:
Iterador são objetos que usam o
next()
método para obter o próximo valor da sequência.Geradores:
Um gerador é uma função que produz ou produz uma sequência de valores usando o
yield
métodoToda
next()
chamada de método no objeto gerador (por exemplo:f
como no exemplo abaixo) retornada pela função do gerador (por exemplo:foo()
função no exemplo abaixo) gera o próximo valor na sequência.Quando uma função geradora é chamada, ela retorna um objeto gerador sem iniciar a execução da função. Quando o
next()
método é chamado pela primeira vez, a função começa a ser executada até atingir a instrução yield que retorna o valor gerado. O rendimento controla ie lembra da última execução. E a segundanext()
chamada continua do valor anterior.O exemplo a seguir demonstra a interação entre rendimento e chamada para o próximo método no objeto gerador.
fonte
Adicionando uma resposta porque nenhuma das respostas existentes aborda especificamente a confusão na literatura oficial.
Funções de gerador são funções comuns definidas usando em
yield
vez dereturn
. Quando chamada, uma função de gerador retorna um objeto gerador , que é um tipo de iterador - ele possui umnext()
método. Quando você chamanext()
, o próximo valor gerado pela função gerador é retornado.A função ou o objeto pode ser chamado de "gerador", dependendo do documento de origem Python que você lê. O glossário do Python diz que funções de gerador, enquanto o wiki do Python implica objetos de gerador. O tutorial do Python notavelmente implica em ambos os usos no espaço de três frases:
As duas primeiras frases identificam geradores com funções geradoras, enquanto a terceira frase os identifica com objetos geradores.
Apesar de toda essa confusão, pode-se procurar a referência da linguagem Python para a palavra clara e final:
Assim, no uso formal e preciso, "gerador" não qualificado significa objeto gerador, não função gerador.
As referências acima são para Python 2, mas a referência à linguagem Python 3 diz a mesma coisa. No entanto, o glossário Python 3 afirma que
fonte
Todo mundo tem uma resposta muito boa e detalhada com exemplos e eu realmente aprecio isso. Eu só queria dar algumas respostas curtas para pessoas que ainda não são muito claras conceitualmente:
Se você criar seu próprio iterador, ele será um pouco envolvido - você precisará criar uma classe e pelo menos implementar o iter e os próximos métodos. Mas e se você não quiser passar por esse aborrecimento e quiser criar rapidamente um iterador. Felizmente, o Python fornece uma maneira rápida de definir um iterador. Tudo o que você precisa fazer é definir uma função com pelo menos 1 chamada para produzir e agora, quando você chamar essa função, ela retornará " algo " que funcionará como um iterador (você pode chamar o próximo método e usá-lo em um loop for). Este algo tem um nome em Python chamado Generator
Espero que isso esclareça um pouco.
fonte
As respostas anteriores perderam essa adição: um gerador tem um
close
método, enquanto os iteradores típicos não. Oclose
método aciona umaStopIteration
exceção no gerador, que pode ser capturada em umafinally
cláusula nesse iterador, para ter a chance de executar alguma limpeza. Essa abstração o torna mais utilizável nos iteradores grandes do que simples. Pode-se fechar um gerador como se pode fechar um arquivo, sem ter que se preocupar com o que está por baixo.Dito isso, minha resposta pessoal à primeira pergunta seria: iterável possui
__iter__
apenas um método, iteradores típicos têm__next__
apenas um método, geradores possuem um__iter__
e um__next__
e um adicionalclose
.Para a segunda pergunta, minha resposta pessoal seria: em uma interface pública, tendem a favorecer muito os geradores, uma vez que é mais resiliente: o
close
método com uma maior composibilidadeyield from
. Localmente, posso usar iteradores, mas apenas se for uma estrutura plana e simples (os iteradores não se compõem facilmente) e se houver motivos para acreditar que a sequência seja bastante curta, especialmente se for interrompida antes de chegar ao fim. Costumo olhar os iteradores como um primitivo de baixo nível, exceto como literais.Para questões de fluxo de controle, os geradores são um conceito tão importante quanto as promessas: ambos são abstratos e composíveis.
fonte
__iter__
método, como um iterador pode ter__next__
apenas? Se eles deveriam ser iterables, eu esperaria que eles__iter__
também o tivessem .__iter__
iterables retorne um iterador, que requer apenas umnext
método (__next__
no Python3). Por favor, não confunda padrões (para digitação de pato) com sua implementação (como um interpretador Python em particular o implementou). É um pouco como a confusão entre as funções do gerador (definição) e os objetos do gerador (implementação). ;)Uma função Generator é como uma função regular no Python, mas contém uma ou mais
yield
instruções. As funções do gerador são uma ótima ferramenta para criar objetos Iterator da maneira mais fácil possível. A função de retorno de objeto Iterator também é chamada de objeto Generator ou Generator .Neste exemplo, eu criei uma função Generator que retorna um objeto Generator
<generator object fib at 0x01342480>
. Assim como outros iteradores, os objetos Generator podem ser usados emfor
loop ou com a funçãonext()
interna que retorna o próximo valor do gerador.Portanto, uma função geradora é a maneira mais fácil de criar um objeto Iterator.
Todo objeto gerador é um iterador, mas não vice-versa. Um objeto iterador personalizado pode ser criado se sua classe implementar
__iter__
e__next__
método (também chamado de protocolo iterador).No entanto, é muito mais fácil usar a função geradores para criar iteradores porque eles simplificam sua criação, mas um Iterador personalizado oferece mais liberdade e você também pode implementar outros métodos de acordo com seus requisitos, conforme mostrado no exemplo abaixo.
fonte
Exemplos de Ned Batchelder altamente recomendados para iteradores e geradores
Um método sem geradores que fazem algo com números pares
enquanto usando um gerador
return
declaraçãoChamar o
evens
método (gerador) é como sempreIterador
e este marcador não tem nada a fazer, exceto mover
next
Para usar o Generator ... precisamos de uma função
Para usar o Iterator ... precisamos
next
eiter
Como foi dito:
Todo o benefício do Iterator:
fonte
Você pode comparar as duas abordagens para os mesmos dados:
Além disso, se você verificar a área ocupada pela memória, o gerador ocupará muito menos memória, pois não precisará armazenar todos os valores na memória ao mesmo tempo.
fonte
Estou escrevendo especificamente para iniciantes em Python de uma maneira muito simples, embora no fundo o Python faça muitas coisas.
Vamos começar com o muito básico:
Considere uma lista,
Vamos escrever uma função equivalente:
o / p de
print(l): [1,2,3]
& o / p deprint(f()) : [1,2,3]
Vamos tornar a lista iterável: na lista python é sempre iterável, o que significa que você pode aplicar o iterador sempre que quiser.
Vamos aplicar o iterador na lista:
Vamos tornar uma função iterável, ou seja, escrever uma função geradora equivalente. Em python, assim que você introduzir a palavra-chave
yield
; torna-se uma função de gerador e o iterador será aplicado implicitamente.Nota: Todo gerador é sempre iterável com o iterador implícito aplicado e aqui o iterador implícito é o ponto crucial. Portanto, a função do gerador será:
Portanto, se você observou, assim que criou a função de gerador, ele já é iter (f)
Agora,
É meio que você está lançando int int (x), que já é int e permanecerá int (x).
Por exemplo, o / p de:
é
Nunca esqueça que este é Python e não C ou C ++
Portanto, a conclusão da explicação acima é:
fonte