Il ciclo for-in in Python è implementato attraverso il protocollo di iterazione, basato su due metodi speciali: __iter__() e __next__(). Quando inizia il ciclo, Python chiama iter(obj) (cerca il metodo __iter__). Se viene restituito un oggetto iteratore, in cui è definito __next__(), il ciclo inizia a chiamare questo metodo per ottenere ogni elemento successivo.
Se l'elemento viene restituito con successo, l'iterazione continua. Quando viene sollevata l'eccezione StopIteration, il ciclo termina.
Esempio di iteratore personalizzato:
class Counter: def __init__(self, low, high): self.current = low self.high = high def __iter__(self): return self def __next__(self): if self.current > self.high: raise StopIteration else: self.current += 1 return self.current - 1 for num in Counter(1, 3): print(num) # Restituirà 1, 2, 3
Sottigliezza: Molte strutture standard di Python implementano il protocollo dell'iteratore; puoi facilmente rendere i tuoi oggetti simili.
È possibile utilizzare il ciclo for-in con qualsiasi oggetto Python? Qual è la differenza tra un oggetto iterabile e un iteratore?
Risposta: No, il ciclo for-in richiede che l'oggetto sia iterabile, cioè deve implementare il metodo __iter__(), che restituisce un iteratore (oggetto con il metodo __next__()). L'iteratore restituisce se stesso tramite __iter__(), mentre l'oggetto iterabile non lo fa.
Esempio:
lst = [1, 2, 3] iterator = iter(lst) print(hasattr(lst, '__iter__')) # True print(hasattr(iterator, '__next__')) # True (iteratore) print(hasattr(lst, '__next__')) # False (non iteratore)
Storia
Progetto: Elaborazione di file di grandi dimensioni.
Problema: Nel progetto si cercava di ripetere il passaggio su un oggetto file (iterazione sulle righe di un file) due volte senza aprire esplicitamente un nuovo file — e nella seconda iterazione non si ottennero righe (il puntatore era già alla fine del file!).
Storia
Progetto: Integrazione della propria classe collezione con il framework.
Problema: La classe implementava solo
__getitem__, ma non__iter__, e non era compatibile con i generatori e i cicli standard (for). Di conseguenza, librerie di terze parti si rompevano, aspettandosi un iteratore.
Storia
Progetto: Utilizzo di map/filter su collezioni personalizzate.
Problema: La propria classe lista non ha implementato
__iter__e__next__, e si è rivelata non compatibile con molte funzioni standard di Python, il che è emerso solo dopo test di integrazione e ha richiesto un notevole ripristino.