Sì, __init__ è il costruttore. Il costruttore è il metodo (i.e., la funzione associata ad una classe) che ti permette di creare un oggetto in uno stato valido.Se non ho capito male con __init__ inizializzo le variabili dell'oggetto passando il valore della lista da scorrere
Non ha senso creare un quadrato senza specificare la lunghezza di un lato, non puoi creare uno studente senza specificare nome, cognome e matricola, non puoi creare una matrice senza specificare la sua dimensione e i valori che contiene e, nel tuo caso, non puoi scorrere i numeri pari se non hai niente da scorrere. Nei casi in cui non ti interessa passare niente al costruttore (e.g., stai creando una linked list e vuoi sempre partire dalla lista vuota) potrai scrivere
def __init__(self))
ma, presumibilmente, dovrai comunque inizializzare alcune "variabile all'interno della classe" (aka., campi) con un valore ragionevole. I metodi __next__ e __iter__ sono quelli che ti permettono di usare il ciclo for. In java diremmo che sono i metodi che sono richiesti dall'interfaccia Iterable. In particolare, __iter__ è il metodo che il ciclo for usa per ottenere un iteratore e __next__ è il metodo che usa per passare al prossimo elemento. Hai bisogno di un metodo __iter__ perché spesso non hai direttamente a che fare con gli iteratori, ma vuoi ottenerne uno da un oggetto di tipo diverso. Per esempio, supponiamo che stai creando una classe per creare un alberi binariil metodo __next__ viene richiamato ed eseguito implicitamente durante il ciclo for
Non ho capito invece __iter__ a cosa serva...
Python:
class BinaryTree:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
# TODO: altri metodi
Python:
class BinaryTree:
def __init__(self, data):
self.data = data
self.left = None
self.right = None
def inorder(self):
return InOrderIterator(self)
def preorder(self):
return PreOrderIterator(self)
def __iter__(self):
return self.inorder()
# TODO: altri metodi (nota: non ho bisogno di __next__)
class InOrderIterator:
def __init__(self, binarytree): # TODO implementazione
def __iter__(self): # TODO implementazione
def __next__(self): # TODO implementazione
class PreOrderIterator:
def __init__(self, binarytree): # TODO implementazione
def __iter__(self): # TODO implementazione
def __next__(self): # TODO implementazione
Python:
tree = BinaryTree(...)
for node in tree: print(node)
for node in tree.inorder(): print(node)
for node in tree.preorder(): print(node)
for node in tere: print(node)
viene chiamato il metodo il metodo __iter__ di BinaryTree e poi viene chiamato per tante volte il metodo __next__ di InOrderIterator.Penso che dopo l'esempio che ti ho fatto sia diventato ovvio. Se vuoi scorrere i numeri pari ti basta un if, ma se vuoi attraversare un albero binario con una visita in-order (o in qualunque altro modo) devi scriverti una spataffiata di codice che è meglio implementare una volta sola e averla lì per sempre piuttosto che reinventartela di volta in volta. Perché non scrivere un metodo stampaInOrder() invece di un iteratore? Perché non necessariamente vuoi stampare i vari nodi, magari vuoi fare una cosa completamente diversa. Io all'interno del for ho scrittoMi domando perchè creare una classe iteratore quando si sarebbe potuto realizzare un codice simile:
oppure creare una classe StampaLista con unaPython:numeri = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] for numero in numeri: if numero % 2 == 0: print(numero)
def stampaPari(lista)
che esegue la stampa dei numeri con la possibilità di aggiungere nella classe un'altradef stampaDispari(lista)
?
print(node)
, ma magari tu stai usando il ciclo for per prendere il massimo, per incrementare il valore di ogni nodo, o per fare una cosa completamente diversa.