This content originally appeared on DEV Community and was authored by bug_elseif
O Iterator é um padrão de projeto comportamental que permite percorrer em elementos de uma coleção sem precisar saber como isso está acontecendo debaixo dos panos, independente de ser lista, pilha, árvore, etc.
Estrutura de dados
Dentre as estruturas citadas acima, vamos utilizar uma árvore como exemplo:
Como podemos ver na imagem acima, a árvore pode ser acessada de diferentes maneiras, de acordo com o solicitado pelo cliente, podendo ter acesso em profundidade ou em largura, além da possibilidade de implementação de outros tipos de acesso aos elementos.
O Iterator é um padrão que extrai essas diferentes formas de percorrer uma árvore para um objeto chamado iterável, segue a imagem:
Exemplo simples:
Implementar um mecanismo de busca, onde o cliente vai utilizar o método getBusca() sem saber com qual algoritmo o método foi desenvolvido - Bubble Sort, Merge Sort, Quick Sort...
Quando usar?
Esse padrão pode ser utilizado quando a complexidade da estrutura de dados não é interessante para o cliente. O acesso aos elementos é fornecido através de métodos simples, encapsulando os detalhes do algoritmo, trazendo mais proteção às coleções, as quais não serão manipuladas diretamente.
Outra vantagem de definir a responsabilidade de percorrer a estrutura de dados para o iterador, tirando ela de dentro da regra de negócio, se dá no tempo que os algoritmos não triviais levam para buscar um elemento. Também pelo fato de que o objeto iterador tem seu próprio estado de iteração, sendo possível mais de um objeto percorrer a mesma coleção em paralelo. Assim o código do cliente se torna mais limpo e focado em seus objetivos.
Iterator no Python
O python possui um módulo Iterator e Iterable, para criar os iteradores e os objetos iteráveis.
from collections.abc import Iterator, Iterable
Este módulo implementa os métodos __iter()__ e __next()__, os quais são necessários para um objeto ser iterável no Python.
import random
class RandomIterable:
def __iter__(self):
return self
def __next__(self):
if random.choice(["go", "go", "stop"]) == "stop":
raise StopIteration
# Sinaliza o fim da iteração
return 1
Criando o iterator.py
Em um arquivo chamado iterator.py, criamos a classe InsertOrder, a qual vai definir a ordem que os elementos de uma coleção serão percorridos - implementamos a função __next()__ aqui.
class InsertOrder(Iterator):
_position: int = None
_reverse: bool = False
def __init__(self, collection: Iterable,
reverse: bool = False) -> None:
self._collection = collection
self._reverse = reverse
self._position = -1 if reverse else 0
def __next__(self):
try:
value = self._collection[self._position]
self._position += -1 if self._reverse else 1
except IndexError:
raise StopIteration()
return value
- classe InsertOrder: possui atributos de posição do elemento e indicação se a coleção deve ser iterada na ordem normal ou reversa
- função __init__: construtor da classe
- função __next__: itera o objeto até não ter mais posições de índices, caindo na except, onde finaliza a iteração, aqui também verificamos se a busca vai ser normal ou reversa
No mesmo arquivo, criamos a classe WordsCollection, essa definirá um objeto iteravel, onde será implementada a segunda função necessária do Iterator, a __iter()__.
class WordsCollection(Iterable):
def __init__(self, collection: list = []) -> None:
self._collection = collection
def __iter__(self) -> InsertOrder:
return InsertOrder(self._collection)
def get_reverse(self) -> InsertOrder:
return InsertOrder(self._collection, True)
def outras_formas(self) -> InsertOrder:
# desenvolver outras formas de percorrer a coleção
...
return InsertOrder(self.colletion)
def add_item(self, item):
self._collection.append(item)
- classe WordsCollection: recebe a estrutura de dados, aqui usamos uma lista para facilitar o entendimento
- função __init__: construtor da classe, ele vai receber a coleção para iterar
- função __iter__: invoca a classe InsertOrder, passa a coleção como parâmetro e retorna um iterador
- função get_reverse: invoca a classe InsertOrder, passa a coleção e a sinalização de ordem reversa como parâmetros e retorna um iterador
- função outras_formas: um exemplo criado sem implementação, podendo criar diferentes regras de busca na mesma coleção, retornando também um iterator
- função add_item: adiciona elementos à uma coleção
Criando o cliente.py
O cliente é quem vai utilizar o iterador, sem precisar saber sobre suas regras de busca, apenas passando a coleção e indicando o método.
def instance_collection(elements: list[str]) -> WordsCollection:
collection = WordsCollection()
for element in elements:
collection.add_item(element)
return collection
- função instance_collection: instancia um objeto iterável, nesse caso uma lista de strings e retorna essa coleção
Executando o cliente.py
if __name__ == '__main__':
elements = [
'IFSC',
'Programação',
'Laboratório',
'Professor',
'Aluno'
]
collection = instance_collection(elements)
- variável elements: definimos uma lista de elementos
- variável collection: chama a função para instanciar um objeto iterável, passando como parametro elements
Iterando pela collection de forma normal:
for e in collection.__iter__():
print(e)
Saída:
IFSC
Programação
Laboratório
Professor
Aluno
Iterando pela collection de forma reversa:
for e in collection.get_reverse():
print(e)
Saída:
Aluno
Professor
Laboratório
Programação
IFSC
Considerações
Com algumas adaptações no iterator.py, podemos fazer a iteração de diversas coleções e estruturas, sem a necessidade de alterar o código cliente.py, pois esse apenas consumirá o iterador.
Conhecendo mais sobre o módulo collections.abc e iterator do Python.
Pessoas que compartilham conhecimentos na comunidade: vcwild
Principal referência para desenvolvimento deste artigo.
Repositório com o código completo.
Enjoy!
This content originally appeared on DEV Community and was authored by bug_elseif
bug_elseif | Sciencx (2022-07-11T04:06:40+00:00) Padrão de projeto – Iterator. Retrieved from https://www.scien.cx/2022/07/11/padrao-de-projeto-iterator/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.