8. Prendere decisioni con le istruzioni if
Nei programmi che abbiamo scritto finora, Python esegue ogni riga di codice dall’alto verso il basso, un’istruzione dopo l’altra. Ma i programmi del mondo reale devono prendere decisioni: eseguire codice diverso a seconda di condizioni diverse. Dovremmo mostrare un messaggio di errore? Dovremmo calcolare uno sconto? Dovremmo chiedere di nuovo l’input? La risposta dipende dalla situazione.
Le istruzioni condizionali permettono ai tuoi programmi di prendere queste decisioni. Consentono a Python di eseguire determinati blocchi di codice solo quando condizioni specifiche sono vere, e di saltarli altrimenti. Questo capitolo introduce l’istruzione if di Python e le sue varianti, che costituiscono la base del processo decisionale nei tuoi programmi.
Padroneggiando le istruzioni condizionali, sarai in grado di scrivere programmi che reagiscono in modo intelligente all’input dell’utente, gestiscono correttamente scenari diversi e risolvono problemi che richiedono ragionamento logico.
8.1) Istruzioni if semplici
La forma più basilare di processo decisionale in Python è l’istruzione if semplice (simple if statement). Dice a Python: "Se questa condizione è vera, esegui questo blocco di codice. Altrimenti, saltalo e continua."
8.1.1) La struttura di un’istruzione if
Ecco la sintassi di base di un’istruzione if:
if condition:
# Codice da eseguire se condition è True
statement1
statement2
# ... altre istruzioniScomponiamo ogni parte:
- La parola chiave
if: avvia l’istruzione condizionale - La condizione: un’espressione booleana che viene valutata come
TrueoFalse(dal Capitolo 7) - I due punti (
:): sono obbligatori e segnano la fine della riga della condizione - Il blocco di codice indentato: tutte le istruzioni indentate sotto l’
ifvengono eseguite solo quando la condizione èTrue
L’indentazione è fondamentale in Python. Le righe indentate formano un blocco di codice (code block) che appartiene all’istruzione if. Python usa l’indentazione (tipicamente 4 spazi) per determinare quali istruzioni fanno parte del blocco condizionale.
Ecco un esempio semplice:
# temperature_check.py
temperature = 30
if temperature > 25:
print("It's a warm day!")
print("Consider wearing light clothing.")
print("Have a great day!") # Questo viene sempre eseguitoOutput:
It's a warm day!
Consider wearing light clothing.
Have a great day!In questo esempio:
- La condizione
temperature > 25viene valutata comeTrue(dato che 30 > 25) - Entrambe le istruzioni
print()indentate vengono eseguite perché fanno parte del bloccoif - L’istruzione
print()finale viene sempre eseguita perché non è indentata: non fa parte del bloccoif
Ora vediamo cosa succede quando la condizione è False:
# temperature_check_cool.py
temperature = 18
if temperature > 25:
print("It's a warm day!")
print("Consider wearing light clothing.")
print("Have a great day!") # Questo viene sempre eseguitoOutput:
Have a great day!Questa volta:
- La condizione
temperature > 25viene valutata comeFalse(dato che 18 non è maggiore di 25) - Entrambe le istruzioni indentate vengono saltate completamente
- Solo il
print()finale viene eseguito perché è fuori dal bloccoif
8.1.2) Usare condizioni dal Capitolo 7
Qualsiasi espressione booleana del Capitolo 7 può essere usata come condizione in un’istruzione if. Questo include:
Operatori di confronto:
# voting_eligibility.py
age = 16
if age >= 18:
print("You are eligible to vote.")
# Non viene stampato nulla perché 16 >= 18 è False
score = 85
if score >= 60:
print("You passed the exam!") # Output: You passed the exam!Test di appartenenza con in e not in:
# user_access.py
username = "alice"
banned_users = ["bob", "charlie", "dave"]
if username not in banned_users:
print(f"Welcome, {username}!") # Output: Welcome, alice!
favorite_color = "blue"
if "u" in favorite_color:
print("Your favorite color contains the letter 'u'.") # Output: Your favorite color contains the letter 'u'.Valori booleani diretti:
# weather_check.py
is_raining = True
if is_raining:
print("Don't forget your umbrella!") # Output: Don't forget your umbrella!Truthiness e falsiness (dal Capitolo 7.4):
# name_input.py
user_input = input("Enter your name: ")
if user_input: # La stringa vuota è falsy, una stringa non vuota è truthy
print(f"Hello, {user_input}!")
else:
print("You didn't enter a name.")8.1.3) Più istruzioni nel blocco if
Puoi includere tutte le istruzioni di cui hai bisogno in un blocco if. Tutte le istruzioni indentate sotto la riga dell’if appartengono a quel blocco:
# bank_withdrawal.py
balance = 1500
withdrawal = 200
if withdrawal <= balance:
balance = balance - withdrawal # Sottrai il prelievo dal saldo
print(f"Withdrawal successful!")
print(f"Your new balance is: ${balance}")
print("Thank you for your transaction.")
print("Transaction complete.") # Viene sempre eseguitoOutput:
Withdrawal successful!
Your new balance is: $1300
Thank you for your transaction.
Transaction complete.Tutte e quattro le istruzioni vengono eseguite perché withdrawal <= balance è True. Se cambiamo il prelievo a 2000:
# bank_withdrawal_insufficient.py
balance = 1500
withdrawal = 2000
if withdrawal <= balance:
balance = balance - withdrawal
print(f"Withdrawal successful!")
print(f"Your new balance is: ${balance}")
print("Thank you for your transaction.")
print("Transaction complete.") # Viene sempre eseguitoOutput:
Transaction complete.Ora nessuna delle istruzioni indentate viene eseguita perché la condizione è False. Il saldo rimane invariato a 1500.
8.2) Usare if-else per scelte aut-aut
Spesso devi scegliere tra due alternative: eseguire un blocco di codice se una condizione è vera, e un blocco diverso se è falsa. L’istruzione if-else gestisce questo processo decisionale aut-aut.
8.2.1) La struttura di if-else
Ecco la sintassi:
if condition:
# Codice da eseguire se condition è True
statement1
statement2
else:
# Codice da eseguire se condition è False
statement3
statement4La clausola else fornisce un percorso alternativo. Esattamente uno dei due blocchi verrà eseguito: mai entrambi, mai nessuno.
Vediamo un esempio pratico:
# age_verification.py
age = int(input("Enter your age: "))
if age >= 18:
print("You are an adult.")
print("You can vote in elections.")
else:
print("You are a minor.")
print("You cannot vote yet.")
print("Thank you for providing your age.")Se inserisci 25:
You are an adult.
You can vote in elections.
Thank you for providing your age.Se inserisci 15:
You are a minor.
You cannot vote yet.
Thank you for providing your age.Nota che esattamente uno dei due blocchi viene eseguito, a seconda della condizione. L’istruzione print() finale viene sempre eseguita perché è fuori da entrambi i blocchi.
8.2.2) Prendere decisioni binarie
if-else è perfetto per decisioni binarie in cui ci sono esattamente due possibili esiti:
# even_odd_checker.py
number = int(input("Enter a number: "))
if number % 2 == 0:
print(f"{number} is even.")
else:
print(f"{number} is odd.")# password_verification.py
stored_password = "python123"
entered_password = input("Enter password: ")
if entered_password == stored_password:
print("Access granted.")
print("Welcome to the system!")
else:
print("Access denied.")
print("Incorrect password.")8.3) Scelte multiple con if-elif-else
Le decisioni del mondo reale spesso coinvolgono più di due opzioni. Dovremmo applicare la spedizione standard, la spedizione express o la spedizione overnight? Un voto è A, B, C, D o F? La catena if-elif-else gestisce più alternative mutuamente esclusive.
8.3.1) La struttura di if-elif-else
Ecco la sintassi:
if condition1:
# Esegui se condition1 è True
block1
elif condition2:
# Esegui se condition1 è False e condition2 è True
block2
elif condition3:
# Esegui se condition1 e condition2 sono False, e condition3 è True
block3
else:
# Esegui se tutte le condizioni sono False
block4Punti chiave sulle catene if-elif-else:
elifè l’abbreviazione di "else if": fornisce condizioni aggiuntive da controllare- L’ordine conta: Python controlla le condizioni dall’alto verso il basso
- Vince la prima corrispondenza: appena una condizione è
True, quel blocco viene eseguito e il resto viene saltato - Esattamente un blocco viene eseguito: al massimo un blocco nella catena verrà eseguito
elseè opzionale: cattura tutti i casi non gestiti dalle condizioni precedenti
Vediamo un esempio pratico:
# grade_calculator.py
score = int(input("Enter your exam score (0-100): "))
if score >= 90:
grade = "A"
print("Excellent work!")
elif score >= 80:
grade = "B"
print("Good job!")
elif score >= 70:
grade = "C"
print("Satisfactory.")
elif score >= 60:
grade = "D"
print("You passed, but consider reviewing the material.")
else:
grade = "F"
print("Unfortunately, you did not pass.")
print(f"Your grade is: {grade}")Se inserisci 85:
Good job!
Your grade is: BVediamo passo passo cosa succede:
- Controlla
score >= 90: False (85 non è >= 90), quindi salta questo blocco - Controlla
score >= 80: True (85 >= 80), quindi esegue questo blocco - Salta tutti i restanti blocchi
elifedelseperché abbiamo trovato una corrispondenza
Se inserisci 55:
Unfortunately, you did not pass.
Your grade is: FTutte le condizioni sono False, quindi viene eseguito il blocco else.
8.3.2) Perché l’ordine conta nelle catene elif
L’ordine delle condizioni è cruciale perché Python smette di controllare non appena trova una condizione True. Considera questo sistema di valutazione errato:
# ORDINE INCORRETTO - Non farlo!
score = 85
if score >= 60: # Questo corrisponderà per primo!
grade = "D"
elif score >= 70:
grade = "C"
elif score >= 80:
grade = "B"
elif score >= 90:
grade = "A"
else:
grade = "F"
print(f"Your grade is: {grade}") # Output: Your grade is: DQuesto dà il risultato sbagliato! Il punteggio 85 dovrebbe essere una B, ma ottiene una D perché score >= 60 viene controllata per prima ed è True. Python non raggiunge mai la condizione score >= 80.
Metti sempre in ordine le condizioni dalla più specifica alla meno specifica:
# ORDINE CORRETTO
score = 85
if score >= 90: # Più specifica
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
elif score >= 60:
grade = "D"
else: # Meno specifica
grade = "F"
print(f"Your grade is: {grade}") # Output: Your grade is: B8.3.3) Usare elif senza else
La clausola else è opzionale. A volte vuoi gestire solo casi specifici e non fare nulla per gli altri:
# weekend_checker.py
day = input("Enter a day of the week: ").lower()
if day == "saturday" or day == "sunday":
print("It's the weekend! Time to relax.")
elif day == "friday":
print("It's Friday! The weekend is almost here.")
elif day in ["monday", "tuesday", "wednesday", "thursday"]:
print("It's a weekday. Time to work or study.")
# Nessuna clausola else - se nessuna corrisponde, non succede nulla
print("Have a great day!")Se inserisci "holiday":
Have a great day!Nessuna condizione corrisponde, e non c’è alcuna clausola else, quindi viene eseguito solo l’ultimo print().
8.4) Istruzioni if annidate
A volte devi prendere una decisione all’interno di un’altra decisione. Le istruzioni if annidate inseriscono un condizionale dentro un altro, permettendoti di controllare condizioni aggiuntive solo dopo che una condizione iniziale è soddisfatta.
8.4.1) Comprendere i condizionali annidati
Le istruzioni if annidate sono potenti perché ti permettono di evitare di controllare condizioni che non hanno ancora senso. Per esempio, non ha senso chiedere una password se l’utente non ha un account. L’annidamento ti consente di strutturare la logica in modo che rispecchi i processi decisionali del mondo reale, in cui alcune domande hanno senso solo dopo che altre hanno ricevuto risposta.
Un’istruzione if annidata è semplicemente un’istruzione if (o una catena if-elif-else) dentro un altro blocco if:
if outer_condition:
# Questo codice viene eseguito se outer_condition è True
if inner_condition:
# Questo codice viene eseguito se ENTRAMBE le condizioni sono True
inner_block
else:
# Questo viene eseguito se outer_condition è True ma inner_condition è False
inner_else_block
else:
# Questo viene eseguito se outer_condition è False
outer_else_blockL’istruzione if interna viene valutata solo se la condizione esterna è True. Questo crea una gerarchia di decisioni.
Ecco un esempio semplice:
# account_login.py
has_account = input("Do you have an account? (yes/no): ").lower() == "yes"
if has_account:
print("Welcome back!")
password = input("Enter your password: ")
if password == "secret123":
print("Login successful!")
print("Access granted to your dashboard.")
else:
print("Incorrect password.")
print("Access denied.")
else:
print("Please create an account first.")
print("Visit our registration page.")Se rispondi "yes" e inserisci la password corretta:
Welcome back!
Login successful!
Access granted to your dashboard.Se rispondi "yes" ma inserisci la password sbagliata:
Welcome back!
Incorrect password.
Access denied.Se rispondi "no":
Please create an account first.
Visit our registration page.Nota come il controllo della password avviene solo se l’utente ha un account. Questo è il beneficio chiave dell’annidamento: puoi evitare controlli non necessari.
8.4.2) Quando usare istruzioni if annidate
Le istruzioni if annidate sono utili quando:
- Le decisioni dipendono da decisioni precedenti: devi controllare qualcosa solo dopo che un’altra condizione è soddisfatta
- Creare alberi decisionali: ogni livello restringe le possibilità
- Validare prerequisiti: controlla i requisiti di base prima di controllare quelli dettagliati
- Evitare controlli non necessari: salta operazioni costose quando le condizioni precedenti falliscono
Esempio: idoneità per un prestito
# loan_eligibility.py
age = int(input("Enter your age: "))
if age >= 18:
print("Age requirement met.")
income = float(input("Enter your annual income: $"))
if income >= 30000:
print("Income requirement met.")
credit_score = int(input("Enter your credit score: "))
if credit_score >= 650:
print("Congratulations! You are eligible for a loan.")
print("Please proceed to the application form.")
else:
print("Sorry, your credit score is too low.")
print("Minimum required: 650")
else:
print("Sorry, your income is too low.")
print("Minimum required: $30,000")
else:
print("Sorry, you must be 18 or older to apply.")Questo crea un albero decisionale in cui ogni livello dipende dal precedente. Se l’età è sotto i 18 anni, non chiediamo mai reddito o credit score.
8.4.3) Evitare un annidamento eccessivo
Anche se l’annidamento è potente, troppi livelli rendono il codice difficile da leggere e capire. Considera questo esempio fortemente annidato:
# Troppo annidato - difficile da seguire
if condition1:
if condition2:
if condition3:
if condition4:
if condition5:
print("All conditions met!")Questo è difficile da leggere e da mantenere. Ecco strategie per ridurre l’annidamento:
Strategia 1: Combinare le condizioni quando appropriato
Studieremo l’operatore and in dettaglio nel Capitolo 9, ma per ora sappi solo che ti permette di controllare più condizioni contemporaneamente:
# Meglio: usa 'and' per combinare condizioni (il Capitolo 9 lo spiegherà completamente)
# Studieremo 'and' nel Capitolo 9, ma per ora sappi solo che controlla
# che tutte le condizioni siano vere
if condition1 and condition2 and condition3 and condition4 and condition5:
print("All conditions met!")Strategia 2: Usare return anticipati (quando si lavora con le funzioni, che studieremo nel Capitolo 19):
# In una funzione, possiamo fare return in anticipo
def check_eligibility(age, income, credit_score):
if age < 18:
return "Too young"
if income < 30000:
return "Income too low"
if credit_score < 650:
return "Credit score too low"
return "Eligible"Strategia 3: Appiattire con elif quando appropriato:
# Invece di if annidati che controllano intervalli
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
# ... e così via8.5) Errori comuni con le istruzioni if (indentazione, due punti e logica)
Anche i programmatori esperti commettono errori con le istruzioni if. Questa sezione copre gli errori più comuni che i principianti incontrano e come evitarli.
8.5.1) Errori di indentazione
Python usa l’indentazione per determinare quali istruzioni appartengono a quale blocco. Un’indentazione errata è una delle fonti di errori più comuni.
Problema 1: Indentazione mancante
# INCORRECT - IndentationError
age = 20
if age >= 18:
print("You are an adult.") # Non indentato!Questo produce:
File "example.py", line 4
print("You are an adult.")
^
IndentationError: expected an indented blockSoluzione: Indenta sempre il blocco sotto un’istruzione if:
# CORRECT
age = 20
if age >= 18:
print("You are an adult.") # Indentato correttamenteProblema 2: Indentazione incoerente
# INCORRECT - Mixing spaces and tabs, or inconsistent spaces
if temperature > 30:
print("It's hot!")
print("Stay hydrated!") # Spazi extra - indentazione incoerenteSoluzione: Usa un’indentazione coerente (4 spazi è lo standard Python):
# CORRECT
if temperature > 30:
print("It's hot!")
print("Stay hydrated!") # Stesso livello di indentazioneProblema 3: Indentazione errata nell’annidamento
# INCORRECT - Wrong indentation level
if has_account:
print("Welcome!")
if password == "correct":
print("Login successful!") # Dovrebbe essere indentato di piùSoluzione: Ogni livello annidato richiede un’indentazione aggiuntiva:
# CORRECT
if has_account:
print("Welcome!")
if password == "correct":
print("Login successful!") # Indentato correttamente per il blocco annidato8.5.2) Due punti mancanti
I due punti (:) alla fine delle righe if, elif ed else sono obbligatori. Dimenticarli è un errore molto comune:
# INCORRECT - SyntaxError: missing colon
if age >= 18
print("Adult")Questo produce:
File "example.py", line 2
if age >= 18
^
SyntaxError: invalid syntaxSoluzione: Includi sempre i due punti:
# CORRECT
if age >= 18:
print("Adult")Lo stesso vale per elif ed else:
# CORRECT - All colons present
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
else:
grade = "F"8.5.3) Operatori di confronto errati
Problema 1: Usare l’assegnazione (=) invece del confronto (==)
# INCORRECT - This assigns 18 to age, doesn't compare!
age = 20
if age = 18: # SyntaxError
print("You are 18")Soluzione: Usa == per confrontare:
# CORRECT
age = 20
if age == 18:
print("You are 18")8.5.4) Codice irraggiungibile a causa di errori di logica
Problema: Condizioni che non possono mai essere True
# INCORRECT - The elif can never execute
score = 85
if score >= 60:
print("You passed!")
elif score >= 80: # This will never execute!
print("You got a B!")Se score è 85, la prima condizione (score >= 60) è True, quindi l’elif non viene mai controllato. L’ordine è sbagliato.
Soluzione: Metti in ordine le condizioni dalla più specifica alla meno specifica:
# CORRECT
score = 85
if score >= 80:
print("You got a B!")
elif score >= 60:
print("You passed!")8.5.5) Blocchi if vuoti
Non puoi avere un blocco if vuoto in Python:
# INCORRECT - SyntaxError
if temperature > 30:
# Aggiungerò qui il codice più tardi
print("Done")Questo produce:
File "example.py", line 3
print("Done")
^
IndentationError: expected an indented blockSoluzione: Usa l’istruzione pass come segnaposto (trattata nella prossima sezione):
# CORRECT - Usare pass come segnaposto
if temperature > 30:
pass # TODO: Aggiungere qui il codice più tardi
print("Done")8.6) Usare pass come segnaposto nei blocchi
A volte, mentre scrivi codice, sai che ti serve un’istruzione if ma non hai ancora deciso quale codice inserirci. Python non consente blocchi di codice vuoti, quindi ti serve un modo per creare un blocco valido ma che "non fa nulla". È qui che entra in gioco l’istruzione pass.
8.6.1) Che cos’è pass?
L’istruzione pass è una operazione nulla (null operation): quando Python la esegue, non succede nulla. È un segnaposto che ti permette di scrivere codice sintatticamente corretto anche quando non hai ancora pronta l’implementazione.
if condition:
pass # Non fare nulla per oraPensa a pass come a un modo per dire a Python: "So che qui mi serve del codice, ma lo aggiungerò più tardi." È particolarmente utile durante lo sviluppo quando stai abbozzando la struttura del programma.
8.6.2) Perché pass è necessario
Python richiede almeno un’istruzione in ogni blocco di codice. Un blocco vuoto causa un errore di sintassi:
# INCORRECT - This causes an error
if age >= 18:
# TODO: Aggiungere qui la logica per adulti
print("Done")Error:
File "example.py", line 3
print("Done")
^
IndentationError: expected an indented blockUsare pass rende il codice sintatticamente valido:
# CORRECT - Using pass as a placeholder
if age >= 18:
pass # TODO: Aggiungere qui la logica per adulti
print("Done")8.6.3) Usi comuni di pass
Uso 1: Segnaposto durante lo sviluppo
Quando stai delineando la struttura del programma ma non hai ancora implementato tutto:
# user_system.py
user_type = input("Enter user type (admin/user/guest): ").lower()
if user_type == "admin":
pass # TODO: Implementare le funzionalità admin
elif user_type == "user":
pass # TODO: Implementare le funzionalità user
elif user_type == "guest":
print("Welcome, guest! Limited access granted.")
else:
print("Invalid user type.")Questo ti permette di eseguire il programma e testare le parti che hai implementato, lasciando segnaposto per lavori futuri.
Uso 2: Non fare intenzionalmente nulla in un ramo
A volte vuoi davvero non fare nulla in certi casi ma devi gestire altri casi:
# positive_numbers.py
# Elabora solo numeri positivi
number = int(input("Enter a number: "))
if number > 0:
result = number * 2
print(f"Double of {number} is {result}")
elif number == 0:
pass # Zero è valido ma non richiede alcuna azione
else:
print("Negative numbers are not allowed.")8.6.4) pass in altri contesti
Anche se ci siamo concentrati su pass nelle istruzioni if, lo incontrerai in altri contesti man mano che impari altro Python:
- Funzioni (functions) (Capitolo 20): segnaposto per i corpi delle funzioni
- Classi (classes) (Capitolo 31): segnaposto per le definizioni delle classi
- Cicli (loops) (Capitoli 11-12): segnaposto per i corpi dei cicli
- Gestori di eccezioni (exception handlers) (Capitolo 29): ignorare intenzionalmente gli errori
Per ora, ricorda che pass è lo strumento per creare blocchi di codice validi ma vuoti quando ne hai bisogno.
Mettere tutto insieme
In questo capitolo, hai imparato come rendere i tuoi programmi intelligenti e reattivi usando le istruzioni condizionali. Ripassiamo i concetti chiave:
Le istruzioni if semplici eseguono codice solo quando una condizione è vera:
if temperature > 30:
print("It's hot outside!")Le istruzioni if-else scelgono tra due alternative:
if age >= 18:
print("Adult")
else:
print("Minor")Le catene if-elif-else gestiscono più opzioni mutuamente esclusive:
if score >= 90:
grade = "A"
elif score >= 80:
grade = "B"
elif score >= 70:
grade = "C"
else:
grade = "F"Le istruzioni if annidate prendono decisioni all’interno di decisioni:
if has_account:
if password_correct:
print("Welcome!")
else:
print("Wrong password")
else:
print("Create an account")Errori comuni da evitare:
- Mancanza dei due punti dopo
if,elifedelse - Indentazione errata o incoerente
- Usare
=invece di==per il confronto - Ordine sbagliato nelle catene
elif - Blocchi vuoti senza
pass
L’istruzione pass funge da segnaposto per blocchi vuoti durante lo sviluppo.
Ora hai gli strumenti per scrivere programmi che prendono decisioni intelligenti in base alle condizioni. Nel prossimo capitolo, impareremo gli operatori di logica booleana (boolean logic operators) (and, or, not) che ti permettono di combinare più condizioni in una logica decisionale più sofisticata. Questo renderà le tue istruzioni if ancora più potenti ed espressive.