Nel capitolo precedente abbiamo imparato a rappresentare dati, eseguire calcoli, lavorare con stringhe e acquisire informazioni dall'utente.
Un programma reale, però, deve anche prendere decisioni e ripetere operazioni.
Al termine di questo capitolo sarai in grado di:
if, elif ed else;and, or e not;for;range() ed enumerate();break e continue;for ... else;while;for e while in base al problema.Finora abbiamo scritto programmi in cui le istruzioni venivano eseguite una dopo l'altra:
name = input("Nome: ")
age = int(input("Età: "))
print(f"Ciao {name}, hai {age} anni")
Questo è un flusso sequenziale.
Nella programmazione, però, abbiamo continuamente bisogno di situazioni come:
"Se succede A, fai B; altrimenti fai C."
oppure:
"Ripeti questa operazione per ogni elemento."
Le strutture di controllo servono proprio a modificare il normale flusso lineare del programma.
Le possiamo raggruppare in due grandi categorie:
STRUTTURE DI CONTROLLO
│
├── Decisioni
│ ├── if
│ ├── elif
│ ├── else
│ └── match
│
└── Ripetizioni
├── for
└── while
A queste si aggiungono strumenti come break, continue, confronti
concatenati e for ... else.
Gli operatori di confronto permettono di confrontare due valori.
Il risultato di un confronto è un valore booleano:
True
oppure:
False
I principali operatori sono:
Operatore Significato Esempio
== uguale a 5 == 5
!= diverso da 5 != 3
> maggiore di 7 > 5
< minore di 3 < 2
>= maggiore o uguale 5 >= 5
<= minore o uguale 4 <= 6
Esempio:
a = 10
b = 5
print(a > b)
print(a == b)
Output:
True
False
= e ==: attenzione!È uno degli errori più comuni dei principianti.
age = 18
è un'assegnazione.
age == 18
è un confronto.
Possiamo leggerli così:
= → assegna
== → confronta
Anche le stringhe possono essere confrontate:
print("apple" == "apple")
print("apple" == "Apple")
Risultato:
True
False
Il confronto distingue maiuscole e minuscole.
Le stringhe possono anche essere confrontate in ordine lessicografico:
print("apple" < "banana")
Il risultato è True.
Per i confronti tra stringhe, però, è importante ricordare che Python utilizza i valori Unicode dei caratteri e non un "ordine alfabetico umano" completo.
== non è isNon bisogna confondere:
== → uguaglianza del valore;is → identità, cioè stesso oggetto.Esempio:
a = [1, 2]
b = [1, 2]
print(a == b)
print(a is b)
Output tipico:
True
False
Le due liste hanno lo stesso contenuto, ma sono due oggetti distinti.
Per ora, quando vogliamo verificare se due valori sono uguali,
utilizziamo normalmente ==.
Dato:
x = 10
y = 5
scrivi espressioni che verifichino:
x è maggiore di y;x è uguale a 10;y è diverso da 10;y è minore o uguale a 5.Qual è il risultato?
print(5 == "5")
Spiega perché.
Qual è la differenza tra:
x = 10
e:
x == 10
if: prendere una decisioneL'istruzione if permette di eseguire un blocco di codice solo quando
una condizione è vera.
La sintassi è:
if condizione:
istruzione
Esempio:
age = 20
if age >= 18:
print("Maggiorenne")
La condizione:
age >= 18
produce True, quindi il print() viene eseguito.
Se invece:
age = 16
la condizione produce False e il blocco non viene eseguito.
Uno degli aspetti più importanti della sintassi Python è l'indentazione.
Dopo i due punti:
if age >= 18:
il codice appartenente al blocco deve essere indentato:
if age >= 18:
print("Maggiorenne")
Possiamo avere più istruzioni nello stesso blocco:
if age >= 18:
print("Maggiorenne")
print("Puoi accedere")
L'indentazione normalmente utilizzata in Python è di quattro spazi.
Non bisogna pensare all'indentazione come a un semplice elemento grafico. In Python definisce realmente la struttura del programma.
Questo:
if True:
print("Uno")
print("Due")
contiene due istruzioni nel blocco if.
Questo:
if True:
print("Uno")
print("Due")
contiene invece una sola istruzione nel blocco.
ifScrivi un programma che stampi "Maggiorenne" quando:
age >= 18
Scrivi un programma che controlli se un numero è positivo:
number = 10
Scrivi un programma che stampi "Disponibile" se:
stock > 0
if ... elseSpesso non vogliamo gestire soltanto il caso vero, ma anche quello falso.
Per questo utilizziamo else:
if condizione:
# caso vero
else:
# caso falso
Esempio:
age = 16
if age >= 18:
print("Maggiorenne")
else:
print("Minorenne")
Uno e uno solo dei due blocchi verrà eseguito.
number = 7
if number % 2 == 0:
print("Pari")
else:
print("Dispari")
Qui utilizziamo ciò che abbiamo imparato nel capitolo precedente:
number % 2
Se il resto è zero, il numero è pari.
if ... elseChiedi all'utente l'età e stampa:
Maggiorenne
oppure:
Minorenne
Chiedi un numero e stampa se è pari o dispari.
Dato:
temperature = 30
stampa "Caldo" se la temperatura è almeno 25, altrimenti
"Non caldo".
if ... elif ... elseQuando abbiamo più alternative possiamo usare elif, abbreviazione di
else if.
Esempio:
score = 8
if score >= 9:
print("Ottimo")
elif score >= 7:
print("Buono")
elif score >= 6:
print("Sufficiente")
else:
print("Insufficiente")
Python valuta le condizioni dall'alto verso il basso.
Non appena trova una condizione vera:
elif successivi;else.Consideriamo:
score = 9
if score >= 6:
print("Sufficiente")
elif score >= 9:
print("Ottimo")
Il risultato sarà:
Sufficiente
perché score >= 6 è già vero.
Quindi una regola fondamentale è:
Con
if / elif / else, l'ordine delle condizioni conta.
È generalmente opportuno mettere prima le condizioni più specifiche o restrittive.
elifScrivi una classificazione:
>= 90 → "A">= 80 → "B">= 70 → "C">= 60 → "D""F"Classifica una temperatura:
"Gelo""Freddo""Mite""Caldo"Spiega perché l'ordine delle condizioni è importante nell'esercizio precedente.
Una condizione può essere costruita combinando più confronti.
Esempio:
age = 30
license = True
if age >= 18 and license:
print("Può guidare")
La condizione è composta da:
age >= 18
e:
license
entrambe vere.
Possiamo anche scrivere:
number = 8
if number > 0 and number % 2 == 0:
print("Numero positivo e pari")
Qui stiamo controllando due proprietà contemporaneamente.
Gli operatori logici principali sono:
Operatore Significato
and entrambe le condizioni devono essere vere
or almeno una condizione deve essere vera
not nega una condizione
andage = 30
print(age >= 18 and age <= 65)
Entrambe le condizioni sono vere, quindi il risultato è True.
orday = "Sunday"
is_weekend = day == "Saturday" or day == "Sunday"
print(is_weekend)
È sufficiente che una delle due condizioni sia vera.
notis_closed = False
print(not is_closed)
Risultato:
True
Quando compaiono più operatori logici, Python segue questa precedenza:
notandorQuindi:
True or False and False
viene interpretato come:
True or (False and False)
e produce:
True
Quando la logica diventa complessa, usare parentesi è spesso una buona idea:
if (age >= 18 and has_license) or is_professional_driver:
...
Le parentesi rendono immediatamente evidente l'intenzione.
In Python una condizione non deve necessariamente essere scritta come:
if valore == True:
Molti oggetti possono essere valutati direttamente in un contesto booleano.
Sono falsy, tra gli altri:
False
None
0
0.0
""
[]
()
{}
set()
Molti altri valori sono truthy.
Esempio:
items = []
if items:
print("Ci sono elementi")
else:
print("Lista vuota")
Con:
items = [1, 2, 3]
il primo blocco viene eseguito.
Questo stile è molto comune in Python:
if name:
print("Nome inserito")
invece di:
if name != "":
print("Nome inserito")
Scrivi una condizione che verifichi se:
Scrivi una condizione vera quando il giorno è "Saturday" oppure
"Sunday".
Che cosa viene stampato?
items = []
if items:
print("A")
else:
print("B")
Indica quali dei seguenti valori sono falsy:
0
"0"
""
[]
[0]
None
La short-circuit evaluation è un comportamento fondamentale di Python.
Quando Python valuta:
A and B
se A è falsy, non ha bisogno di valutare B: il risultato è già
determinato.
Analogamente, con:
A or B
se A è truthy, B non deve essere valutato.
Esempio:
False and print("Non verrà eseguito")
La seconda parte non viene eseguita.
Analogamente:
True or print("Non verrà eseguito")
non esegue il secondo print().
Questo comportamento è particolarmente utile quando una seconda operazione deve essere eseguita solo se la prima condizione è soddisfatta.
Esempio:
items = []
if items and items[0] == 10:
print("Il primo elemento è 10")
Python valuta:
items
che è falsy perché la lista è vuota.
Di conseguenza non valuta:
items[0] == 10
e non si verifica IndexError.
Un altro esempio:
user = None
if user and user.is_admin():
print("Accesso consentito")
Se user è None, Python non tenta di eseguire user.is_admin().
and e or non restituiscono necessariamente True o FalseQuesto è un dettaglio molto importante.
Gli operatori and e or in Python restituiscono uno degli operandi,
non necessariamente un booleano.
Esempio:
name = "" or "Anonimo"
print(name)
Risultato:
Anonimo
Perché "" è falsy, quindi viene restituito il secondo valore.
Altro esempio:
name = "Mario" or "Anonimo"
print(name)
Risultato:
Mario
Un pattern molto comune è:
config = input("Configurazione: ") or "default"
Se l'utente non inserisce nulla, viene utilizzato "default".
Con and:
token = "abc123" and "OK"
print(token)
risultato:
OK
Che cosa viene stampato?
print(False and print("Hello"))
Che cosa viene stampato?
name = "" or "Guest"
print(name)
Scrivi una condizione sicura che acceda al primo elemento di una lista solo quando la lista non è vuota.
Python permette di scrivere più confronti consecutivi in una forma molto simile alla matematica.
Per esempio:
0 < x < 20
è equivalente a:
0 < x and x < 20
Esempio:
age = 35
if 18 <= age <= 65:
print("Fascia considerata")
Questo è particolarmente leggibile.
Possiamo concatenare anche più confronti:
0 < x < 10 < y
Python valuta la catena in modo equivalente a:
0 < x and x < 10 and 10 < y
con la particolarità che gli elementi intermedi vengono valutati in modo appropriato senza ripetizioni inutili.
Non scrivere:
18 <= age and age <= 65
se:
18 <= age <= 65
esprime chiaramente la stessa intenzione.
La forma concatenata è uno degli aspetti più eleganti di Python.
Scrivi con un confronto concatenato:
x è maggiore o uguale a 10 e minore di 20
Verifica se un voto è compreso tra 6 incluso e 10 incluso.
Spiega la differenza tra:
0 < x < 10
e:
0 < x and x < 10
Python possiede una forma compatta per esprimere una semplice scelta tra due valori:
valore_se_vero if condizione else valore_se_falso
È spesso chiamata operatore ternario, anche se più precisamente si tratta di un'espressione condizionale.
Esempio:
age = 20
status = "Maggiorenne" if age >= 18 else "Minorenne"
print(status)
La versione estesa sarebbe:
if age >= 18:
status = "Maggiorenne"
else:
status = "Minorenne"
number = 7
parity = "pari" if number % 2 == 0 else "dispari"
È utile quando la condizione è breve e il risultato è immediatamente comprensibile.
Da evitare quando la logica diventa complicata:
# difficile da leggere
result = "A" if x > 10 else "B" if x > 5 else "C"
In quel caso è preferibile:
if x > 10:
result = "A"
elif x > 5:
result = "B"
else:
result = "C"
Crea:
status = "adult" if age >= 18 else "minor"
usando una variabile age.
Dato un numero, crea una variabile contenente "pari" oppure
"dispari".
Riscrivi un'espressione ternaria troppo complessa utilizzando
if / elif / else.
match ... caseA partire da Python 3.10 è disponibile match ... case.
È particolarmente utile quando dobbiamo confrontare un valore con diverse alternative.
Esempio:
choice = int(input("Scegli (1-3): "))
match choice:
case 1:
print("Inserisci")
case 2:
print("Modifica")
case 3:
print("Elimina")
case _:
print("Scelta non valida")
Il caso:
case _:
funziona come caso predefinito.
if/elif o match?Non esiste una regola secondo cui uno debba sempre sostituire l'altro.
Usiamo spesso if quando stiamo valutando condizioni:
if age >= 18:
match è particolarmente naturale quando confrontiamo un valore con
alternative discrete:
match command:
case "start":
...
case "stop":
...
matchCrea un menu:
1 - Inserisci
2 - Cerca
3 - Elimina
4 - Esci
e gestiscilo con match.
Dato:
day = "Saturday"
usa match per distinguere alcuni giorni della settimana.
forLe condizioni permettono di scegliere.
I cicli permettono di ripetere.
Il for viene utilizzato per iterare sugli elementi di un
iterabile.
Sintassi:
for variabile in iterabile:
istruzioni
Esempio:
numbers = [1, 2, 3, 4]
for number in numbers:
print(number)
Output:
1
2
3
4
Il for non richiede normalmente di gestire manualmente un indice:
Python prende un elemento alla volta dall'iterabile e lo assegna alla
variabile del ciclo.
range()range() è uno degli strumenti più utilizzati nei cicli.
for i in range(5):
print(i)
Output:
0
1
2
3
4
Attenzione:
range(5)arriva fino a4: il valore finale5è escluso.
Possiamo utilizzare:
range(start, stop)
per esempio:
for i in range(1, 6):
print(i)
Output:
1
2
3
4
5
Possiamo anche specificare il passo:
for i in range(1, 10, 2):
print(i)
Output:
1
3
5
7
9
Il passo può essere negativo:
for i in range(5, 0, -1):
print(i)
Output:
5
4
3
2
1
for e range()Stampa i numeri da 0 a 9.
Stampa i numeri da 1 a 10.
Stampa tutti i numeri pari da 2 a 20.
Stampa il conto alla rovescia da 10 a 1.
Una stringa è un iterabile.
Possiamo quindi scrivere:
word = "Python"
for letter in word:
print(letter)
Output:
P
y
t
h
o
n
Questo è molto utile quando dobbiamo analizzare caratteri singolarmente.
Esempio:
word = "banana"
count = 0
for letter in word:
if letter == "a":
count += 1
print(count)
Il risultato è:
3
Stampa ogni carattere della parola:
word = "Programming"
Conta quante volte compare la lettera "a".
Conta quante vocali contiene una parola.
Suggerimento:
vowels = "aeiou"
e usa in.
enumerate()A volte non ci basta conoscere il valore: vogliamo anche la sua posizione.
Possiamo utilizzare enumerate():
names = ["Anna", "Luca", "Marco"]
for index, name in enumerate(names):
print(index, name)
Output:
0 Anna
1 Luca
2 Marco
Possiamo modificare l'indice iniziale:
for index, name in enumerate(names, start=1):
print(index, name)
Output:
1 Anna
2 Luca
3 Marco
Questo è generalmente preferibile a:
for i in range(len(names)):
print(i, names[i])
quando ci serve semplicemente indice + valore.
enumerate()Stampa una lista di prodotti numerandoli a partire da 1.
Dato:
names = ["Anna", "Luca", "Marco"]
stampa:
1. Anna
2. Luca
3. Marco
Anche un dizionario è iterabile.
Per impostazione predefinita, iterare sul dizionario significa iterare sulle chiavi:
student = {
"name": "Anna",
"age": 20
}
for key in student:
print(key)
Possiamo ottenere i valori:
for value in student.values():
print(value)
Oppure chiavi e valori:
for key, value in student.items():
print(key, value)
Questo ultimo schema è molto comune.
Dato:
student = {
"name": "Anna",
"age": 20,
"course": "Python"
}
stampa tutte le chiavi.
Stampa tutte le coppie chiave-valore nel formato:
name: Anna
age: 20
course: Python
breakbreak interrompe immediatamente il ciclo nel quale si trova.
Esempio:
for number in range(10):
if number == 5:
break
print(number)
Output:
0
1
2
3
4
Quando number diventa 5, viene eseguito break e il ciclo termina.
names = ["Anna", "Luca", "Marco", "Sara"]
for name in names:
if name == "Marco":
print("Trovato")
break
Non è necessario continuare a cercare dopo aver trovato l'elemento.
continuecontinue non termina il ciclo.
Salta invece il resto dell'iterazione corrente e passa alla successiva.
Esempio:
for number in range(5):
if number == 2:
continue
print(number)
Output:
0
1
3
4
Il valore 2 viene saltato.
Un uso tipico è ignorare dati che non ci interessano:
numbers = [1, -2, 3, -4, 5]
for number in numbers:
if number < 0:
continue
print(number)
Output:
1
3
5
break e continueScorri:
numbers = [3, 7, 2, 9, 10, 5]
e interrompi il ciclo quando trovi 10.
Stampa solo i numeri positivi:
numbers = [3, -2, 5, -8, 10]
usando continue.
Qual è la differenza tra break e continue?
for ... elsePython permette di associare un else a un ciclo for.
L'else viene eseguito quando il ciclo termina normalmente, cioè
senza essere interrotto da break.
Esempio:
numbers = [1, 3, 5, 7]
for number in numbers:
if number % 2 == 0:
print("Numero pari trovato")
break
else:
print("Nessun numero pari")
Non viene trovato alcun numero pari e non viene eseguito break, quindi
l'else viene eseguito.
Con:
numbers = [1, 3, 4, 7]
il break viene eseguito e l'else non viene eseguito.
Non pensare:
"
elseappartiene all'if."
Pensa invece:
"
elseappartiene alfore viene eseguito se il ciclo non è stato interrotto conbreak."
Questo costrutto è particolarmente utile per le ricerche.
for ... elseCerca un numero pari in una lista e stampa:
Numero pari trovato
oppure:
Nessun numero pari
usando for ... else.
Cerca la lettera "z" nella parola "python" usando for ... else.
Per capire veramente il for, dobbiamo introdurre il concetto di
iterabile.
Un iterabile è un oggetto che può essere attraversato elemento per elemento.
Sono iterabili, tra gli altri:
list;tuple;set;dict;str;range;Per esempio:
for character in "Python":
print(character)
funziona perché una stringa è iterabile.
Anche:
for number in [1, 2, 3]:
print(number)
funziona perché una lista è iterabile.
I due termini non sono sinonimi.
Un iterabile è un oggetto dal quale possiamo ottenere un iteratore.
Un iteratore è un oggetto che restituisce gli elementi uno alla volta.
Possiamo osservare il meccanismo:
numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator))
print(next(iterator))
print(next(iterator))
Output:
1
2
3
Dopo l'ultimo elemento, un'ulteriore chiamata a next() produce
StopIteration.
Il ciclo for gestisce automaticamente questo meccanismo.
In forma concettuale:
iterabile
↓ iter()
iteratore
↓ next()
elemento
↓
elemento
↓
elemento
Per questo non è necessario scrivere manualmente iter() e next()
nella maggior parte dei programmi.
Molte funzioni Python lavorano direttamente con iterabili:
numbers = [1, 2, 3, 4, 5]
print(sum(numbers))
print(min(numbers))
print(max(numbers))
Possiamo anche usare:
any()
all()
Esempio:
numbers = [2, 4, 6]
print(all(number % 2 == 0 for number in numbers))
Risultato:
True
E:
numbers = [1, 3, 4, 7]
print(any(number % 2 == 0 for number in numbers))
Risultato:
True
Queste forme sono già un primo assaggio di strumenti che approfondiremo più avanti.
Indica quali dei seguenti oggetti sono iterabili:
[1, 2, 3]
"Python"
42
range(10)
{"a": 1}
Usa sum() per calcolare:
[10, 20, 30, 40]
Usa any() per verificare se esiste almeno un numero negativo in:
numbers = [3, 7, -2, 9]
whileIl ciclo while ripete un blocco finché una condizione è vera.
Sintassi:
while condizione:
istruzioni
Esempio:
counter = 0
while counter < 5:
print(counter)
counter += 1
Output:
0
1
2
3
4
La differenza concettuale rispetto al for è importante.
Il for è normalmente utilizzato quando vogliamo attraversare un
iterabile:
for item in items:
Il while è particolarmente adatto quando la fine del ciclo dipende da
una condizione:
while password != correct_password:
while e l'aggiornamento della condizioneUn errore molto comune è dimenticare di modificare qualcosa che permetta alla condizione di diventare falsa.
Questo programma è problematico:
counter = 0
while counter < 5:
print(counter)
counter rimane sempre 0.
La condizione:
counter < 5
rimane quindi sempre vera.
La versione corretta è:
counter = 0
while counter < 5:
print(counter)
counter += 1
Quando counter arriva a 5, la condizione diventa falsa e il ciclo
termina.
while e input dell'utenteUn uso tipico del while è ripetere una richiesta finché l'utente non
inserisce un valore valido.
Esempio:
password = ""
while password != "python":
password = input("Inserisci la password: ")
print("Accesso consentito")
Il numero di tentativi non è noto in anticipo.
Questo è un caso naturale per while.
Una versione più robusta, che limita i tentativi, sarà possibile quando approfondiremo ulteriormente condizioni e gestione degli errori.
while con breakPossiamo utilizzare un ciclo apparentemente infinito e decidere esplicitamente quando uscire:
while True:
command = input("Comando: ")
if command == "exit":
break
print(f"Hai scritto: {command}")
Questo schema è molto comune nei programmi interattivi.
Il significato è:
continua a chiedere comandi finché l'utente non inserisce
exit.
while con continueAnche while supporta continue.
counter = 0
while counter < 5:
counter += 1
if counter == 3:
continue
print(counter)
Output:
1
2
4
5
È importante aggiornare il contatore prima del continue;
altrimenti potremmo creare un ciclo infinito.
while ... elseAnche while può avere un else.
L'else viene eseguito quando il ciclo termina normalmente, senza
break.
counter = 0
while counter < 3:
print(counter)
counter += 1
else:
print("Ciclo terminato normalmente")
Output:
0
1
2
Ciclo terminato normalmente
Se invece il ciclo viene interrotto:
counter = 0
while counter < 3:
if counter == 1:
break
print(counter)
counter += 1
else:
print("Ciclo terminato normalmente")
l'else non viene eseguito.
whileStampa i numeri da 1 a 10 usando while.
Scrivi un programma che continui a chiedere un comando finché l'utente non scrive:
exit
Utilizza while per calcolare la somma dei numeri da 1 a 100.
Spiega perché questo ciclo non termina:
i = 0
while i < 5:
print(i)
Un ciclo infinito è un ciclo che non termina.
Il caso più esplicito è:
while True:
print("Infinito")
La condizione è sempre vera.
Un ciclo infinito non è necessariamente un errore.
Può essere intenzionale in:
Per esempio:
while True:
command = input("Comando: ")
if command == "exit":
break
Il ciclo è infinito solo fino a quando non viene ricevuto il comando di uscita.
Un errore tipico è:
i = 0
while i < 5:
print(i)
Manca:
i += 1
quindi la condizione non cambia mai.
Possiamo interrompere un ciclo in diversi modi.
Nel contesto che stiamo studiando:
breakwhile True:
if condition:
break
returnAll'interno di una funzione, return termina la funzione e quindi anche
il ciclo che si trova al suo interno.
Ctrl + CDurante l'esecuzione da terminale possiamo normalmente interrompere un programma con:
Ctrl + C
che genera un'interruzione, generalmente visibile come
KeyboardInterrupt.
Individua il problema:
i = 1
while i <= 10:
print(i)
Trasforma:
while True:
...
in un menu che termini quando l'utente sceglie 0.
Un ciclo può contenere un altro ciclo.
Si parla di cicli annidati o nested loops.
Esempio:
for i in range(3):
for j in range(2):
print(i, j)
Output:
0 0
0 1
1 0
1 1
2 0
2 1
Per ogni valore di i, il ciclo interno viene eseguito completamente.
Possiamo visualizzarlo così:
i = 0 → j = 0, 1
i = 1 → j = 0, 1
i = 2 → j = 0, 1
I cicli annidati sono particolarmente utili per strutture a righe e colonne.
Esempio:
matrix = [
[1, 2, 3],
[4, 5, 6]
]
for row in matrix:
for value in row:
print(value)
Output:
1
2
3
4
5
6
Possiamo anche visualizzare una tabella:
for i in range(1, 6):
for j in range(1, 6):
print(i * j, end="\t")
print()
Il secondo print() serve per andare a capo dopo ogni riga.
break nei cicli annidatiAttenzione: un break interrompe il ciclo più interno nel quale viene
eseguito.
Esempio:
for i in range(3):
for j in range(3):
if j == 1:
break
print(i, j)
Il break interrompe il ciclo su j, non quello su i.
Questa distinzione è importante quando i cicli diventano più complessi.
Se un ciclo esegue n operazioni e contiene un secondo ciclo che esegue
n operazioni per ogni iterazione, possiamo avere circa:
n × n = n²
operazioni.
In termini di complessità:
un ciclo → O(n)
due cicli → O(n²)
tre cicli → O(n³)
Non significa che ogni programma con due for sia automaticamente
O(n²): la complessità reale dipende da ciò che fanno i cicli e dalle
dimensioni degli input.
Il concetto da ricordare è:
I cicli annidati possono far crescere rapidamente il lavoro necessario al programma.
Utilizza due cicli per stampare tutte le coppie:
(1, 1)
(1, 2)
(2, 1)
(2, 2)
(3, 1)
(3, 2)
Costruisci una tabella 5 × 5 contenente i prodotti tra righe e colonne.
Data:
matrix = [
[1, 2],
[3, 4],
[5, 6]
]
stampa tutti gli elementi usando cicli annidati.
for e whileUna domanda importante è:
Quando devo utilizzare
fore quandowhile?
Una regola pratica è:
for quando devi attraversare un iterabilefor product in products:
print(product)
oppure quando il numero di iterazioni è definito:
for i in range(10):
...
while quando la ripetizione dipende da una condizionewhile balance > 0:
...
oppure quando non sai in anticipo quante iterazioni saranno necessarie:
while command != "exit":
command = input("Comando: ")
Non esiste però una regola assoluta.
Lo stesso problema può spesso essere risolto con entrambi i costrutti. La scelta migliore è quella che rende più evidente l'intenzione del programma.
Possiamo ora combinare condizioni e cicli.
Partiamo da:
numbers = [3, 7, 2, 9, 4, 10, 5]
for number in numbers:
if number % 2 == 0:
print(number, "pari")
else:
print(number, "dispari")
count = 0
for number in numbers:
if number > 5:
count += 1
print("Numeri > 5:", count)
found = False
for number in numbers:
if number > 8:
found = True
break
print("Esiste un numero > 8:", found)
Possiamo anche utilizzare any():
found = any(number > 8 for number in numbers)
Entrambe le soluzioni sono corrette. La prima è utile per comprendere il meccanismo dei cicli; la seconda è più compatta.
for number in numbers:
if number < 0:
print("Numero negativo trovato")
break
else:
print("Nessun numero negativo")
whileindex = 0
total = 0
while index < len(numbers):
total += numbers[index]
index += 1
print("Somma totale:", total)
In questo caso sum(numbers) sarebbe naturalmente più semplice, ma il
while ci permette di esercitarci sul controllo manuale dell'indice.
Data:
numbers = [3, 7, 2, 9, 4, 10, 5]
calcola quanti numeri sono pari.
Trova il primo numero maggiore di 8 utilizzando break.
Verifica con for ... else se nella lista sono presenti numeri
negativi.
Calcola la somma usando while.
Prova a rispondere prima di guardare le soluzioni.
Qual è il risultato?
print(5 == "5")
TrueFalseQual è il risultato?
x = 10
print(0 < x < 20)
TrueFalseQuale messaggio viene visualizzato?
print(False and print("Hello"))
HelloQual è il risultato?
x = 0
print(x or 10)
0False10Qual è il risultato?
age = 17
status = "OK" if age >= 18 else "NO"
print(status)
OKNOQual è il risultato?
print(not (True or False))
TrueFalseQual è il risultato?
a = 5
b = 10
print(a < b == 10)
TrueFalseFalse: un intero e una stringa non sono lo stesso valore.True.Hello: and si ferma sul primo valore falsy.10: 0 è falsy.NO.False.True: equivale a a < b and b == 10.È arrivato il momento di combinare tutto ciò che abbiamo studiato.
Realizza un programma che analizzi una serie di numeri.
Partiamo da:
numbers = [3, 7, 2, 9, 4, 10, 5]
Il programma deve:
for;5;8;for ... else che non esistano numeri negativi;while;10;=== ANALISI NUMERI ===
3 → dispari
7 → dispari
2 → pari
9 → dispari
4 → pari
10 → pari
5 → dispari
Numeri maggiori di 5: 3
Esiste un numero maggiore di 8: True
Nessun numero negativo
Somma totale: 40
Trovato 10: ciclo interrotto
Per questa versione utilizza:
if / elif / else;for;while;break;continue dove opportuno;for ... else;Puoi utilizzare anche len(), any() e sum(), ma prova prima a
risolvere il problema con i cicli per esercitarti.
Una possibile soluzione è:
numbers = [3, 7, 2, 9, 4, 10, 5]
print("=== ANALISI NUMERI ===")
print()
# 1–2. Pari o dispari
for number in numbers:
if number % 2 == 0:
print(f"{number} → pari")
else:
print(f"{number} → dispari")
# 3. Conteggio dei numeri > 5
count = 0
for number in numbers:
if number > 5:
count += 1
print()
print(f"Numeri maggiori di 5: {count}")
# 4. Verifica dell'esistenza di un numero > 8
found = False
for number in numbers:
if number > 8:
found = True
break
print(f"Esiste un numero maggiore di 8: {found}")
# 5. Verifica dei numeri negativi
for number in numbers:
if number < 0:
print("Numero negativo trovato")
break
else:
print("Nessun numero negativo")
# 6. Somma con while
index = 0
total = 0
while index < len(numbers):
total += numbers[index]
index += 1
print(f"Somma totale: {total}")
# 7. Interruzione quando viene trovato 10
for number in numbers:
if number == 10:
print("Trovato 10: ciclo interrotto")
break
Dopo aver compreso bene i cicli, alcune operazioni possono essere espresse in modo più compatto:
numbers = [3, 7, 2, 9, 4, 10, 5]
count_greater_than_5 = sum(number > 5 for number in numbers)
has_number_greater_than_8 = any(number > 8 for number in numbers)
total = sum(numbers)
print(f"Numeri maggiori di 5: {count_greater_than_5}")
print(f"Esiste un numero maggiore di 8: {has_number_greater_than_8}")
print(f"Somma totale: {total}")
Qui compare un concetto interessante: in Python bool è un sottotipo di
int, quindi True e False possono essere utilizzati numericamente
in contesti come questo. Tuttavia, questa forma va utilizzata solo
quando rende il codice realmente più chiaro.
La prima soluzione rimane fondamentale dal punto di vista didattico perché mostra esplicitamente come si costruiscono i risultati.
In questo capitolo abbiamo imparato a controllare il flusso dei programmi Python.
Abbiamo visto che:
= serve per l'assegnazione, mentre == confronta due valori;if permette di eseguire codice condizionatamente;elif permette di gestire più alternative;else gestisce il caso alternativo;and, or e not permettono di combinare condizioni;and e or possono restituire gli operandi e non necessariamente
True o False;match ... case è utile per confrontare un valore con diverse
alternative;for permette di attraversare un iterabile;range() genera una sequenza di valori utilizzabile nei cicli;enumerate() permette di ottenere indice e valore;break interrompe un ciclo;continue salta l'iterazione corrente;for ... else permette di gestire il caso in cui una ricerca
termini senza break;next();while ripete un blocco finché una condizione rimane vera;for e while dipende dal problema che vogliamo
risolvere.Abbiamo quindi aggiunto al nostro modello mentale un elemento fondamentale:
Capitolo 1
DATI
↓
variabili → tipi → operatori → stringhe
↓
Capitolo 2
CONTROLLO DEL FLUSSO
↓
decisioni → ripetizioni → ricerca → iterazione
Nel prossimo capitolo potremo utilizzare queste strutture per lavorare con una delle caratteristiche più importanti di Python: le collezioni di dati, iniziando dalle liste e imparando a creare, modificare e attraversare strutture dati sempre più ricche.