In python un iteratore è un oggetto su cui è possibile iterare, ritorna un elemento per volta e implementa lo "iterator protocol", che consiste in due metodi:

  • __iter__(): ritorna l'oggetto iteratore(per esempio viene utilizzato nel for loop);
  • __next__(): ritorna il prossimo valore dell'iteratore, se non ce ne sono più solleva una eccezione StopIteration.

Cos'è un iterabile

Dizionari, liste, tuple e stringhe sono tutti oggetti iterabili, ovvero dei veri e propri contenitori da cui puoi ottenere l'iteratore tramite il metodo iter() e il valore successivo applicando next() all'iteratore.

lista_iterabile = ["pythonpertutti", "python", "ananas"]
iteratore = iter(lista_iterabile)
print(next(iteratore)) #output: pythonpertutti print(next(iteratore)) #output: python print(next(iteratore)) #output: ananas print(next(iteratore)) #output: exception StopIteration.

Interagire con un iteratore

Per iterare tramite un oggetto iterabile possiamo utilizzare un for loop:

>>> tupla = (1, 2, 3, 4)
>>> for elemento in tupla:
... print(elemento)

Fondamentalmente questo loop crea un iteratore dalla tupla ed esegue il metodo next() fino a quando non viene sollevata l'eccezione StopIteration.

Creare un iteratore

Per creare un oggetto iteratore dobbiamo implementare i due metodi citati inizialmente: __iter__() e __next__() e il costruttore della classe __init__(). Vediamo per esempio come creare un iteratore che ritorna un numero alla ennesima potenza:

class Potenza:
    def __init__(self, base):
        self.base = base
    
    def __iter__(self):
        self.numero = self.base
        return self
        
    def __next__(self):
        self.numero_successivo = self.numero
        self.numero = self.numero * self.base
        return self.numero_successivo



if __name__ == '__main__':
    mia_classe = Potenza(2)
    iteratore_mia_classe = iter(mia_classe)

    print(next(iteratore_mia_classe))
    #output: 2
    print(next(iteratore_mia_classe))
    #output: 4
    print(next(iteratore_mia_classe))
    #output: 8
    print(next(iteratore_mia_classe))
    #output: 16
    print(next(iteratore_mia_classe))
    #output: 32
    print(next(iteratore_mia_classe))
    #output: 64
    print(next(iteratore_mia_classe))
    #output: 128

In questo caso abbiamo un iteratore "infinito", in quanto, se per esempio implementassimo un for loop, l'esecuzione girerebbe per sempre.

Dare un limite agli iteratori

Per evitare tutto ciò possiamo giocare sull'eccezione StopIteration:

class Potenza:
    def __init__(self, base):
        self.base = base
        self.esponente = 1
def __iter__(self): self.numero = self.base return self def __next__(self): if self.esponente <= 5: self.numero_successivo = self.numero self.numero = self.numero * self.base self.esponente += 1 return self.numero_successivo else: raise StopIteration if __name__ == '__main__': mia_classe = Potenza(2) iteratore_mia_classe = iter(mia_classe) for numero in mia_classe: print(numero)

In questo modo potrò ottenere dall'iteratore al massimo la quinta potenza del numero che ho indicato.

Conclusione

Bene! Siamo giunti al termine del post... ora sai come funziona un iteratore e come crearne uno.

Spero di esserti stato utile e se lo sono stato ti invito a condividere l'articolo sui social e a seguirmi su twitter e instagram, alla prossima!


Condividi sui Social