Iteradores Python (__iter__ e __next__): como usar e por quê?

Iteradores são objetos que podem ser iterados. Neste tutorial, você aprenderá como o iterador funciona e como pode construir seu próprio iterador usando os métodos __iter__ e __next__.

Vídeo: Iteradores Python

Iteradores em Python

Os iteradores estão por toda parte em Python. Eles são elegantemente implementados em forloops, compreensões, geradores etc., mas estão escondidos à vista de todos.

Iterator em Python é simplesmente um objeto que pode ser iterado. Um objeto que retornará dados, um elemento por vez.

Tecnicamente falando, um objeto iterador Python deve implementar dois métodos especiais __iter__()e __next__(), coletivamente chamados de protocolo iterador .

Um objeto é chamado de iterável se pudermos obter um iterador dele. A maioria dos contêineres integrados em Python, como: list, tuple, string etc., são iteráveis.

A iter()função (que por sua vez chama o __iter__()método) retorna um iterador deles.

Iterando por meio de um Iterador

Usamos a next()função para iterar manualmente por todos os itens de um iterador. Quando chegarmos ao final e não houver mais dados a serem retornados, será lançada a StopIterationExceção. A seguir está um exemplo.

 # define a list my_list = (4, 7, 0, 3) # get an iterator using iter() my_iter = iter(my_list) # iterate through it using next() # Output: 4 print(next(my_iter)) # Output: 7 print(next(my_iter)) # next(obj) is same as obj.__next__() # Output: 0 print(my_iter.__next__()) # Output: 3 print(my_iter.__next__()) # This will raise error, no items left next(my_iter)

Resultado

 4 7 0 3 Traceback (última chamada mais recente): Arquivo "", linha 24, na próxima (my_iter) StopIteration

Uma maneira mais elegante de iterar automaticamente é usar o loop for. Usando isso, podemos iterar sobre qualquer objeto que pode retornar um iterador, por exemplo, lista, string, arquivo etc.

 >>> for element in my_list:… print(element)… 4 7 0 3

Trabalho de loop for para Iteradores

Como vemos no exemplo acima, o forloop foi capaz de iterar automaticamente pela lista.

Na verdade, o forloop pode iterar em qualquer iterável. Vamos dar uma olhada em como o forloop é realmente implementado no Python.

 for element in iterable: # do something with element

Na verdade, é implementado como.

 # create an iterator object from that iterable iter_obj = iter(iterable) # infinite loop while True: try: # get the next item element = next(iter_obj) # do something with element except StopIteration: # if StopIteration is raised, break from loop break

Portanto, internamente, o forloop cria um objeto iterador, iter_objchamando iter()no iterável.

Ironicamente, esse forloop é na verdade um loop while infinito.

Dentro do loop, ele chama next()para obter o próximo elemento e executa o corpo do forloop com esse valor. Depois que todos os itens se esgotam, StopIterationé levantado que é capturado internamente e o laço termina. Observe que qualquer outro tipo de exceção passará.

Criação de iteradores personalizados

Construir um iterador do zero é fácil em Python. Só precisamos implementar __iter__()os __next__()métodos e.

O __iter__()método retorna o próprio objeto iterador. Se necessário, alguma inicialização pode ser realizada.

O __next__()método deve retornar o próximo item na sequência. Ao chegar ao fim, e nas chamadas subsequentes, deve aumentar StopIteration.

Aqui, mostramos um exemplo que nos dará a próxima potência de 2 em cada iteração. O expoente de potência começa de zero até um número definido pelo usuário.

Se você não tem nenhuma idéia sobre programação orientada a objetos, visite Python Object-Oriented Programming.

 class PowTwo: """Class to implement an iterator of powers of two""" def __init__(self, max=0): self.max = max def __iter__(self): self.n = 0 return self def __next__(self): if self.n <= self.max: result = 2 ** self.n self.n += 1 return result else: raise StopIteration # create an object numbers = PowTwo(3) # create an iterable from the object i = iter(numbers) # Using next to get to the next iterator element print(next(i)) print(next(i)) print(next(i)) print(next(i)) print(next(i))

Resultado

 1 2 4 8 Traceback (última chamada mais recente): Arquivo "/home/bsoyuj/Desktop/Untitled-1.py", linha 32, impresso (próximo (i)) Arquivo "", linha 18, em __next__ aumentar StopIteration StopIteration

Também podemos usar um forloop para iterar nossa classe iteradora.

 >>> for i in PowTwo(5):… print(i)… 1 2 4 8 16 32

Iteradores infinitos Python

Não é necessário que o item em um objeto iterador tenha que ser esgotado. Pode haver infinitos iteradores (que nunca termina). Devemos ter cuidado ao lidar com esses iteradores.

Aqui está um exemplo simples para demonstrar iteradores infinitos.

A iter()função embutida function pode ser chamada com dois argumentos, onde o primeiro argumento deve ser um objeto chamável (função) e o segundo é o sentinela. O iterador chama essa função até que o valor retornado seja igual ao sentinela.

 >>> int() 0 >>> inf = iter(int,1) >>> next(inf) 0 >>> next(inf) 0

Podemos ver que a int()função sempre retorna 0. Portanto, passá-la como iter(int,1)retornará um iterador que chama int()até que o valor retornado seja igual a 1. Isso nunca acontece e obtemos um iterador infinito.

Também podemos construir nossos próprios iteradores infinitos. O iterador a seguir irá, teoricamente, retornar todos os números ímpares.

 class InfIter: """Infinite iterator to return all odd numbers""" def __iter__(self): self.num = 1 return self def __next__(self): num = self.num self.num += 2 return num

Uma execução de amostra seria a seguinte.

 >>> a = iter(InfIter()) >>> next(a) 1 >>> next(a) 3 >>> next(a) 5 >>> next(a) 7

E assim por diante…

Tenha o cuidado de incluir uma condição de término ao iterar esses tipos de iteradores infinitos.

A vantagem de usar iteradores é que eles economizam recursos. Como mostrado acima, poderíamos obter todos os números ímpares sem armazenar todo o sistema numérico na memória. Podemos ter itens infinitos (teoricamente) na memória finita.

Existe uma maneira mais fácil de criar iteradores em Python. Para saber mais, visite: Geradores Python usando rendimento.

Artigos interessantes...