Iteratori

Python SELF IT
Livello 19 , Lezione 4
Disponibile

5.1 Iterable e Iterator

Come già sai, gli iteratori sono oggetti che implementano il protocollo dell'iteratore, permettendo di ottenere gli elementi di una collezione uno per uno. Gli iteratori sono ampiamente usati in Python per scorrere gli elementi di sequenze come liste, tuple e stringhe.

Vediamo come sono strutturati gli iteratori e come utilizzarli.

Oggetto Iterabile (Iterable)

Affinché un oggetto possa essere attraversato con un ciclo for, deve essere iterabile – un Iterable. Ciò significa che il nostro oggetto deve implementare il metodo __iter__(), che restituisce un oggetto-iteratore.

Oggetto-iteratore (Iterator)

È un oggetto speciale che possiede la funzione __next__() per restituire l'elemento successivo della sequenza. Quando gli elementi finiscono, il metodo __next__() lancia l'eccezione StopIteration come segnale di fine iterazione.

L'iteratore deve anche implementare il metodo __iter__(), che restituisce l'iteratore stesso.

Esempio usando funzioni integrate di Python

In questo esempio, la lista numbers è un oggetto iterabile. Otteniamo l'iteratore usando la funzione iter() e usiamo la funzione next() per scorrere gli elementi fino a quando non viene lanciata l'eccezione StopIteration.


# Oggetto iterabile
numbers = [1, 2, 3, 4, 5]
            
# Otteniamo l'iteratore dall'oggetto iterabile
iterator = iter(numbers)
            
# Usiamo l'iteratore per scorrere gli elementi
try:
    while True:
        number = next(iterator)
        print(number)
except StopIteration:
    pass
        

Proprio quello che succede quando scrivi il codice tipo:


# Oggetto iterabile
numbers = [1, 2, 3, 4, 5]
            
for number in numbers:
    print(number)
        

5.2 L'essenza dell'iteratore

Un iteratore è un certo oggetto che ci aiuta a scorrere un gruppo di elementi uno per uno. Le implementazioni possono essere molto diverse. Scriviamo la nostra classe, dove realizziamo tutti i requisiti richiesti da un iteratore.

Passo 1. Creiamo la nostra classe

Facciamola restituire i numeri da start a end


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        

Passo 2. Supporto della funzione __iter__

Ora dobbiamo aggiungere la funzione __iter__, che restituirà l'oggetto-iteratore su cui verrà chiamata la funzione __next()__. Stiamo tornando al nostro stesso oggetto – questo non è vietato.


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        

Passo 3. Supporto della funzione __next__

Ora dobbiamo aggiungere al nostro oggetto iteratore la funzione __next__, che restituirà l'elemento successivo della nostra lista. Usiamo semplicemente la variabile current:


def __next__(self):
    current = self.current
    self.current += 1
    return current
        

Passo 4. Fermare l'iteratore

Se l'iteratore ha già restituito tutti i valori previsti, dovrebbe lanciare l'eccezione StopIteration. Aggiustiamo un po' la nostra ultima funzione:


def __next__(self):
    if self.current >= self.end:
        raise StopIteration
    current = self.current
    self.current += 1
    return current
        

Ottimo. Ora possiamo usare il nostro iteratore. Ecco un esempio del nostro intero codice:


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        current = self.current
        self.current += 1
        return current
        
# Creiamo un'istanza di un iteratore personalizzato
my_iter = MyIterator(1, 5)
        
# Usiamo l'iteratore per scorrere gli elementi
for num in my_iter:
    print(num)

5.3 Un iteratore corretto

Cosa c'è che non va nell'iteratore dell'esempio precedente? Sì, è un iteratore, funziona, ma è troppo semplice. Non consente di scorrere la stessa collezione di elementi contemporaneamente con diversi iteratori.

Sarebbe più corretto scrivere del codice che non restituisse un riferimento a se stesso nel metodo __iter__, ma un oggetto separato, che restituisse correttamente tutti gli elementi.

Esempio:


class MyIterable:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        return MyIterator(self.data)
    
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        item = self.data[self.index]
        self.index += 1
        return item
    
# Utilizzo
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
    print(item)
    

In questo esempio abbiamo due classi - la prima prende una collezione, sulla quale intendiamo iterare. E la seconda è l'iteratore, che restituisce gli elementi della collezione nel metodo next(). Anche se è abbastanza semplice, è proprio così che dovresti aggiungere iteratori alle tue classi.

1
Опрос
Moduli e package,  19 уровень,  4 лекция
недоступен
Moduli e package
Moduli e package
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION