Iterabile
L’iterabile è di base un contenitore di oggetti, e dà accesso a tutti gli oggetti in sequenza. La qualità di un iterabile è la temporalità, e non la spazialità, perchè non sevre avere un oggetto con tutti i valori, ma i valori possono essere generati quando servono, uno alla volta.
range
L’oggetto range è un iterabile, e rappresenta un intervallo di interi.
range([iniziale], limite, [incremento])
Il valore iniziale di default è 0, e quello di incremento è +1. Il limite è escluso dall’intervallo.
Trasformazione in tupla o lista
Un iterabile si può trasformare facilmente in una tupla o in una lista tramite due metodi list(i) e tuple(i). Un esempio pratico può essere:
list(range(10)) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
tuple(range(5)) # (0, 1, 2, 3, 4)title: I file sono iterabili
Un file aperto è un iterabile, e itera sulle righe.Un iterabile, però, deve avere una controparte computazionale, chiamata iteratore.
Iteratore
Un iteratore è una struttura che sa come generare/recuperare gli elementi del suo iterabile.
iteratore = iter(R) o iteratore = R.__iter__(), con R un iterabile, ritorna un iteratore.
next(iteratore) o iteratore.__next__() restituisce l’elemento successivo. Se l’iterabile è arrivato in fondo, solleva un errore StopIteration, che si può gestire con un catch.
Ovviamente
id(iteratore) == id(R)produce falso, perchè sono due oggetti completamente differenti.
La struttura for in realtà non è altro che zucchero sintattico per una struttura un pelo più lunga da scrivere, ovvero il while:
while True:
try:
e = next(I)
except StopIteration:
break
else:
print(e)
Di seguito una implementazione custom di un iterabile con annesso iteratore.
class my_range:
class my_range_iterator:
def __init__(self, start,end,step):
self.s=start
self.e=end
self.p=step
def __next__(self):
if (self.p>0 and self.s>=self.e) or \
(self.p<0 and self.s<=self.e):
raise StopIteration
val = self.s
self.s += self.p
return val
def __init__(self,*args):
'''
Un oggetto my range deve essere inizializzato un range,
e dunque con un numero di parametri variabile fra 1 e 3
'''
if (n:=len(args)) and n>3:
raise TypeError(f"my_range expected at most 3 arguments, got {n}")
for x in args:
if type(x) is not int:
raise TypeError(f"'{type(x)}' object cannot be interpreted as an integer")
if n==1:
self.start = 0
self.end = args[0]
self.step = 1
else:
self.start = args[0]
self.end = args[1]
self.step = 1 if n==2 else args[2]
def __iter__(self):
return my_range.my_range_iterator(self.start,self.end,self.step)Un oggetto può fare contemporaneamente sia da iterabile che da iteratore.