Iterador Python vs Iterável

Resumo : neste tutorial, você aprenderá sobre iterador e iterável Python e suas diferenças.

Iteradores

Um iterador é um objeto que implementa o protocolo do iterador. Em outras palavras, um iterador é um objeto que implementa os seguintes métodos:

  • __iter__retorna o próprio objeto iterador.
  • __next__retorna o próximo elemento.

Depois de concluir a iteração de uma coleção usando um iterador, o iterador fica esgotado. Isso significa que você não pode mais usar o objeto iterador.

Iteráveis

Um iterável é um objeto sobre o qual você pode iterar.

Um objeto é iterável quando implementa o __iter__método. E seu __iter__método retorna um novo iterador.

Examinando a lista integrada e o iterador de lista

Em Python, uma lista é uma coleção ordenada de itens. Também é iterável porque um objeto de lista possui o __iter__método que retorna um iterador. Por exemplo:

numbers = [1, 2, 3]

number_iterator = numbers.__iter__()
print(type(number_iterator))Linguagem de código:  Python  ( python )

Saída:

<class 'list_iterator'>Linguagem de código:  HTML, XML  ( xml )

Neste exemplo, o __iter__método retorna um iterador com o tipo list_iterator.

Como list_iteratorimplementa o __iter__método, você pode usar a iterfunção integrada para obter o objeto iterador:

numbers = [1, 2, 3]
number_iterator = iter(numbers)Linguagem de código:  Python  ( python )

Como list_iteratortambém implementa o __next__método, você pode usar a função integrada nextpara iterar na lista:

numbers = [1, 2, 3]

number_iterator = iter(numbers)

next(number_iterator)
next(number_iterator)
next(number_iterator)Linguagem de código:  Python  ( python )

Se você chamar a nextfunção mais uma vez, receberá uma StopIterationexceção.

next(number_iterator)

Erro:

StopIterationLinguagem de código:  JavaScript  ( javascript )

Isso ocorre porque o iterador da lista se esgotou. Para iterar a lista novamente, você precisa criar um novo iterador.

Isso ilustra a separação da lista de seu iterador. A lista é criada uma vez, enquanto o iterador é criado sempre que você precisa iterar na lista.

Iterador Python e Iterável

O seguinte define a Colorsclasse:

class Colors:
    def __init__(self):
        self.rgb = ['red', 'green', 'blue']
        self.__index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.__index &gt;= len(self.rgb):
            raise StopIteration

        # return the next color
        color = self.rgb[self.__index]
        self.__index += 1
        return colorLinguagem de código:  Python  ( python )

Neste exemplo, a Colorsclasse desempenha duas funções: iterável e iteradora.

A Colorsclasse é um iterador porque implementa o método __iter__e __next__. O __iter__método retorna o próprio objeto. E o __next__método retorna o próximo item de uma lista.

A Colorsclasse também é iterável porque implementa o __iter__método que retorna um objeto em si, que é um iterador.

O seguinte cria uma nova instância da Colorsclasse e itera sobre seus elementos usando um forloop:

colors = Colors()

for color in colors:
    print(color)Linguagem de código:  Python  ( python )

Depois de concluir a iteração, o colorsobjeto se torna inútil. Se você tentar iterá-lo novamente, receberá uma StopIterationexceção:

next(colors)Linguagem de código:  Python  ( python )

Erro:

StopIterationLinguagem de código:  JavaScript  ( javascript )

Se você usar o forloop, não receberá nada em troca. O iterador está vazio:

for color in colors:
    print(color)Linguagem de código:  Python  ( python )

Para iterar novamente, você precisa criar um novo colorsobjeto com o rgbatributo. Isso é ineficiente.

Separando um iterador de um iterável

Vamos separar o iterador de cores de seu iterável, como o Python faz com o iterador de lista e a lista.

O seguinte define a Colorsclasse:

class Colors:
    def __init__(self):
        self.rgb = ['red', 'green', 'blue']

    def __len__(self):
        return len(self.rgb)Linguagem de código:  Python  ( python )

O seguinte define a ColorIteratorclasse:

class ColorIterator:
    def __init__(self, colors):
        self.__colors = colors
        self.__index = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.__index >= len(self.__colors):
            raise StopIteration

        # return the next color
        color = self.__colors.rgb[self.__index]
        self.__index += 1
        return colorLinguagem de código:  Python  ( python )

Como funciona.

  • O __init__método aceita um iterável que é uma instância da Colorsclasse.
  • O __iter__método retorna o próprio iterador.
  • O método __next__ retorna o próximo elemento do Colorsobjeto.

O exemplo a seguir mostra como usar o ColorIteratorpara iterar sobre o Colorsobjeto:

colors = Colors()
color_iterator = ColorIterator(colors)

for color in color_iterator:
    print(color)Linguagem de código:  Python  ( python )

Para iterar o Colorsobjeto novamente, basta criar uma nova instância do arquivo ColorIterator.

Há um problema!

Quando quiser iterar o Colorsobjeto, você precisará criar manualmente um novo ColorIteratorobjeto. E você também precisa se lembrar do nome do iterador ColorIterator.

Seria ótimo se você pudesse automatizar isso. Para fazer isso, você pode tornar a Colorsclasse iterável implementando o __iter__método:

class Colors:
    def __init__(self):
        self.rgb = ['red', 'green', 'blue']

    def __len__(self):
        return len(self.rgb)

    def __iter__(self):
        return ColorIterator(self)
Linguagem de código:  Python  ( python )

O __iter__método retorna uma nova instância da ColorIteratorclasse.

Agora, você pode iterar o Colorsobjeto sem criá-lo explicitamente ColorIterator:

colors = Colors()

for color in colors:
    print(color)
Linguagem de código:  Python  ( python )

Internamente, o forloop chama o __iter__método do colorsobjeto para obter o iterador e usa esse iterador para iterar sobre os elementos do colorsobjeto.

O seguinte coloca a ColorIteratorclasse dentro da Colorsclasse para encapsulá-las em uma única classe:

class Colors:
    def __init__(self):
        self.rgb = ['red', 'green', 'blue']

    def __len__(self):
        return len(self.rgb)

    def __iter__(self):
        return self.ColorIterator(self)

    class ColorIterator:
        def __init__(self, colors):
            self.__colors = colors
            self.__index = 0

        def __iter__(self):
            return self

        def __next__(self):
            if self.__index >= len(self.__colors):
                raise StopIteration

            # return the next color
            color = self.__colors.rgb[self.__index]
            self.__index += 1
            return color
Linguagem de código:  Python  ( python )

Resumo

  • Um iterável é um objeto que implementa o __iter__método que retorna um iterador.
  • Um iterador é um objeto que implementa o __iter__método que retorna a si mesmo e o __next__método que retorna o próximo elemento.
  • Iteradores também são iteráveis.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *