A melhor forma de abstrair as nossas iterações é fazer os nossos próprios objectos iteráveis. Neste post veremos como podemos tornar os nossos objectos em iteráveis.

class ListaTarefas(objecto):
    def __init__(self):
        self.tarefas = []

    def __iter__(self):
        return iter(self.tarefas)



lista_de_tarefas = ListaTarefas():
...

for tarefa in lista_de_tarefas:
    #...

A forma de tornar os nossos objectos em iteráveis é implementando o método especial ___iter__(). A única coisa que o método ___iter__() faz é devolver um qualquer tipo de iterador.

A forma mais simples de tornar um objecto num iterável é usar a função iter() numa qualquer colecção de dados que tenhamos. No caso acima temos uma lista de tarefas (self.tarefas), e a função __iter__() pode simplesmente devolver iter(self.tarefas).

Uma vez feito isto, o nosso objecto pode ser iterado tal como qualquer outro iterável em Python. No código acima usámos um ciclo for, mas pode também ser usado de todas as outras formas em que os iteráveis podem ser usados.

class ListaTarefas(objecto):
    def __init__(self):
        self.tarefas = []

    def __iter__(self):
        for tarefa in self.tarefas:
            if not tarefa.concluida:
                yield tarefa
    
    def todas(self):
        return iter(self.tarefas)

    def concluidas(self)
        return (t for t in self.tarefas if t.concluida)
        

Uma maneira mais poderosa de implementar a função __iter__() é usar um generator. De recordar que ao chamar um generator é devolvido um iterador, que é o que faz a função __iter__().

No código acima alteramos a classe ListaTarefas para produzir apenas as tarefas não concluídas quando for iterada.

Relembro que os objectos iteráveis podem ser iterados em mais do que uma maneira. Podemos também ter outros métodos que produzam iteradores. Na classe ListaTarefas temos o método todas() que devolve todas as tarefas, devolvendo apenas um iterador para a lista self.tarefas e o método concluidas() devolve as tarefas concluídas utilizando uma expressão de generator. As expressões de generator (Generator expressions) têm uma sintaxe similar às List comprehensions, mas em vez de devolverem uma lista devolvem um iterador.

Usei três técnicas diferentes nos três métodos que devolvem iteradores, apenas como demonstração das várias possibilidades que o Python permite. A ideia é providenciar iteração customizada utilizando todas as ferramentas que a linguagem de programação Python nos disponibiliza.



E agora só falta a conclusão, para terminar com esta série de posts sobre os ciclos em Python.


Este post faz parte da série de posts sobre Ciclos e Interáveis em Python:
  1. Ciclos em Python, o básico
  2. Ciclos em Python e os Iteráveis
  3. Ciclos em Python, mais exemplos de Iteráveis
  4. Ciclos em Python, uso de Iteráveis fora dos ciclos
  5. Ciclos em Python, problemas comuns e os índices
  6. Ciclos em Python, iterar sobre duas listas
  7. Ciclos em Python, iteração personalizada
  8. Ciclos em Python, Generators - parte 1
  9. Ciclos em Python, Generators - parte 2
  10. Ciclos em Python, Generators - parte 3
  11. Ciclos em Python, operações de baixo nível
  12. Ciclos em Python, como tornar os nossos objectos em Iteráveis (post actual)
  13. Ciclos em Python, conclusão


A inspiração para este post veio daqui.