Python & AI Tutorials Logo
Programmazione Python

9. Combinare condizioni con la logica booleana

Nel Capitolo 7, abbiamo imparato i valori booleani e le condizioni semplici usando gli operatori di confronto. Nel Capitolo 8, abbiamo usato queste condizioni per prendere decisioni con le istruzioni if. Ma i programmi del mondo reale spesso devono verificare più condizioni contemporaneamente. Dovremmo concedere l’accesso se l’utente ha la password corretta e ha effettuato l’accesso? Dovremmo mostrare un avviso se la temperatura è troppo calda o troppo fredda? Dovremmo procedere se il file non è vuoto?

Python fornisce tre operatori logici che ci permettono di combinare e modificare i valori booleani: and, or e not. Questi operatori sono i mattoni fondamentali per esprimere una logica decisionale complessa nei tuoi programmi.

9.1) Operatori logici and, or e not

I tre operatori logici lavorano con valori booleani (o valori che possono essere trattati come booleani) per produrre nuovi risultati booleani.

9.1.1) L’operatore and

L’operatore and restituisce True solo quando entrambi gli operandi sono veri. Se uno dei due operandi è falso, l’intera espressione è falsa.

python
# Entrambe le condizioni devono essere vere
age = 25
has_license = True
 
can_rent_car = age >= 21 and has_license
print(can_rent_car)  # Output: True
 
# Se una delle condizioni è falsa, il risultato è False
age = 18
can_rent_car = age >= 21 and has_license
print(can_rent_car)  # Output: False

Pensa a and come a un guardiano severo: tutte le condizioni devono essere soddisfatte affinché il controllo complessivo vada a buon fine.

Tabella di verità per and:

Operando sinistroOperando destroRisultato
TrueTrueTrue
TrueFalseFalse
FalseTrueFalse
FalseFalseFalse

9.1.2) L’operatore or

L’operatore or restituisce True quando almeno uno degli operandi è vero. Restituisce False solo quando entrambi gli operandi sono falsi.

python
# Almeno una condizione deve essere vera
is_weekend = True
is_holiday = False
 
can_sleep_in = is_weekend or is_holiday
print(can_sleep_in)  # Output: True
 
# Entrambe le condizioni false
is_weekend = False
is_holiday = False
can_sleep_in = is_weekend or is_holiday
print(can_sleep_in)  # Output: False

Pensa a or come a un guardiano indulgente: basta soddisfare una condizione per passare.

Tabella di verità per or:

Operando sinistroOperando destroRisultato
TrueTrueTrue
TrueFalseTrue
FalseTrueTrue
FalseFalseFalse

Ecco un esempio pratico per un sistema di idoneità a uno sconto:

python
# Il cliente ottiene lo sconto se è uno studente OPPURE un anziano
age = 68
is_student = False
 
gets_discount = is_student or age >= 65
print(f"Eligible for discount: {gets_discount}")  # Output: Eligible for discount: True
 
# Un altro cliente
age = 30
is_student = False
gets_discount = is_student or age >= 65
print(f"Eligible for discount: {gets_discount}")  # Output: Eligible for discount: False

Il primo cliente è idoneo perché soddisfa uno dei criteri (anziano), anche se non è uno studente.

9.1.3) L’operatore not

L’operatore not è un operatore unario (lavora su un singolo operando) che inverte un valore booleano. Trasforma True in False e False in True.

python
is_raining = False
is_sunny = not is_raining
print(is_sunny)  # Output: True
 
is_raining = True
is_sunny = not is_raining
print(is_sunny)  # Output: False

Tabella di verità per not:

OperandoRisultato
TrueFalse
FalseTrue

L’operatore not è particolarmente utile quando vuoi verificare l’opposto di una condizione:

python
# Controlla se un file NON è vuoto
file_size = 0
is_empty = file_size == 0
is_not_empty = not is_empty
print(f"File has content: {is_not_empty}")  # Output: File has content: False
 
# Controlla se l'utente NON ha effettuato l'accesso
is_logged_in = False
needs_login_prompt = not is_logged_in
print(f"Show login prompt: {needs_login_prompt}")  # Output: Show login prompt: True

9.1.4) Combinare più operatori logici

Puoi combinare più operatori logici in un’unica espressione per costruire condizioni più sofisticate:

python
# Negozio online: spedizione gratuita se l'ordine supera i $50 OPPURE il cliente è premium
# E gli articoli sono disponibili
order_total = 45.00
is_premium = True
in_stock = True
 
gets_free_shipping = (order_total >= 50 or is_premium) and in_stock
print(f"Free shipping: {gets_free_shipping}")  # Output: Free shipping: True

Tracciamo questa valutazione:

  1. order_total >= 50 valuta False (45.00 non è >= 50)
  2. is_premium è True
  3. False or True valuta True
  4. in_stock è True
  5. True and True valuta True

Ecco un altro esempio con il controllo degli accessi:

python
# L'utente può accedere al pannello admin se è un admin
# E (si trova nella rete interna OPPURE usa una VPN)
is_admin = True
on_internal_network = False
using_vpn = True
 
can_access_admin = is_admin and (on_internal_network or using_vpn)
print(f"Can access admin panel: {can_access_admin}")  # Output: Can access admin panel: True

Nota le parentesi attorno a (on_internal_network or using_vpn). Sono importanti perché controllano l’ordine di valutazione, proprio come le parentesi nelle espressioni aritmetiche.

9.2) Precedenza degli operatori nelle espressioni booleane (ordine Not, And, Or)

Quando combini più operatori logici senza parentesi, Python segue regole di precedenza specifiche per determinare l’ordine di valutazione. Comprendere queste regole ti aiuta a scrivere condizioni corrette ed evitare bug sottili.

9.2.1) La gerarchia di precedenza

Python valuta gli operatori logici in questo ordine (dalla precedenza più alta alla più bassa):

  1. not (precedenza più alta)
  2. and (precedenza media)
  3. or (precedenza più bassa)

Questo significa che not viene valutato per primo, poi and e infine or.

python
# Senza parentesi, la precedenza determina l'ordine
result = True or False and False
print(result)  # Output: True
 
# Come Python valuta questo:
# Step 1: False and False → False (and ha precedenza più alta di or)
# Step 2: True or False → True

Vediamolo passo dopo passo con un esempio più dettagliato:

python
is_weekend = False
is_holiday = True
has_work = True
 
# Espressione: not has_work or is_weekend and is_holiday
free_time = not has_work or is_weekend and is_holiday
 
# Ordine di valutazione:
# Step 1: not has_work → not True → False
# Step 2: is_weekend and is_holiday → False and True → False
# Step 3: False or False → False
print(f"Has free time: {free_time}")  # Output: Has free time: False

9.2.2) Usare le parentesi per chiarezza

Anche quando comprendi le regole di precedenza, usare le parentesi rende il codice più chiaro e previene errori. Le parentesi sovrascrivono la precedenza predefinita e rendono esplicite le tue intenzioni.

python
# Ambiguo senza parentesi
result = True or False and False
print(result)  # Output: True
 
# Chiaro con le parentesi - cosa intendevamo davvero?
result = (True or False) and False
print(result)  # Output: False
 
result = True or (False and False)
print(result)  # Output: True

Queste due espressioni producono risultati diversi! Le parentesi cambiano completamente il significato.

9.2.3) Operatori di confronto e operatori logici insieme

Gli operatori di confronto (come <, >, ==, !=) hanno precedenza più alta degli operatori logici. Questo significa che i confronti vengono valutati prima delle operazioni logiche.

python
age = 25
income = 50000
 
# Non servono parentesi attorno ai confronti
eligible = age >= 18 and income >= 30000
print(f"Eligible for loan: {eligible}")  # Output: Eligible for loan: True
 
# Python lo valuta come:
# Step 1: age >= 18 → True
# Step 2: income >= 30000 → True
# Step 3: True and True → True

9.3) Valutazione short-circuit

Python usa la valutazione short-circuit quando valuta espressioni booleane con and e or. Questo significa che Python smette di valutare non appena conosce il risultato finale, saltando potenzialmente la valutazione di operandi successivi. Questo comportamento è sia un’ottimizzazione delle prestazioni sia una tecnica di programmazione utile.

9.3.1) Come short-circuita and

Con l’operatore and, se l’operando sinistro è False, Python sa che l’intera espressione deve essere False (perché entrambi gli operandi devono essere veri affinché and restituisca True). Di conseguenza, Python non valuta affatto l’operando destro.

python
# Dimostrazione semplice
x = 5
result = x < 3 and x > 10
print(result)  # Output: False
 
# Valutazione di Python:
# Step 1: x < 3 → 5 < 3 → False
# Step 2: Poiché il lato sinistro è False, non valutare x > 10
# Step 3: Restituisci False

Ecco un esempio pratico che mostra perché la valutazione short-circuit è importante:

python
# Verifica se un numero è divisibile - evitando la divisione per zero
numerator = 100
denominator = 0
 
# Questo è sicuro grazie alla valutazione short-circuit
# Se denominator è 0, la divisione non avviene mai
is_divisible = denominator != 0 and numerator % denominator == 0
print(f"Is divisible: {is_divisible}")  # Output: Is divisible: False
 
# Senza valutazione short-circuit, questo causerebbe un errore:
# denominator = 0
# result = numerator % denominator  # ZeroDivisionError!

L’espressione denominator != 0 valuta False, quindi Python non valuta mai numerator % denominator, che causerebbe un errore di divisione per zero.

Vediamo un altro esempio con operazioni sulle stringhe:

python
# Controllare in modo sicuro le proprietà di una stringa
text = ""
 
# Controlla se text non è vuoto E il primo carattere è maiuscolo
# Sicuro perché se text è vuoto, non proviamo mai ad accedere a text[0]
has_uppercase_start = len(text) > 0 and text[0].isupper()
print(f"Starts with uppercase: {has_uppercase_start}")  # Output: Starts with uppercase: False
 
# Se provassimo questo senza il controllo della lunghezza:
# text = ""
# result = text[0].isupper()  # IndexError: string index out of range

9.3.2) Come short-circuita or

Con l’operatore or, se l’operando sinistro è True, Python sa che l’intera espressione deve essere True (perché è sufficiente che almeno un operando sia vero). Di conseguenza, Python non valuta l’operando destro.

python
# Dimostrazione semplice
x = 15
result = x > 10 or x < 5
print(result)  # Output: True
 
# Valutazione di Python:
# Step 1: x > 10 → 15 > 10 → True
# Step 2: Poiché il lato sinistro è True, non valutare x < 5
# Step 3: Restituisci True

9.3.3) Applicazioni pratiche della valutazione short-circuit

Evitare errori:

python
# Accedere in modo sicuro agli elementi di una lista
numbers = [1, 2, 3]
index = 5
 
# Controlla se index è valido prima di accedere
is_valid = index < len(numbers) and numbers[index] > 0
print(f"Valid and positive: {is_valid}")  # Output: Valid and positive: False
 
# Senza short-circuit, questo andrebbe in crash:
# is_valid = numbers[index] > 0  # IndexError!

Verificare più condizioni in modo efficiente:

python
# Validazione di un form - fermarsi al primo errore
email = "user@example.com"
password = "pass"
age = 25
 
# Verifica ogni requisito in ordine di probabilità di fallimento
valid_form = (
    len(email) > 0 and              # Controllo rapido
    "@" in email and                # Controllo rapido
    len(password) >= 8 and          # Controllo rapido
    age >= 18                       # Controllo rapido
)
print(f"Form valid: {valid_form}")  # Output: Form valid: False
# Si ferma al controllo sulla lunghezza della password, non valuta age

No

No

Espressione and

Lato sinistro True?

Restituisci False
Salta il lato destro

Valuta il lato destro

Restituisci il risultato destro

Espressione or

Lato sinistro True?

Restituisci True
Salta il lato destro

Valuta il lato destro

Restituisci il risultato destro

9.4) Cosa restituiscono gli operatori and e or con operandi non booleani e comuni insidie nelle espressioni booleane

Finora, abbiamo visto and, or e not funzionare con valori booleani. Ma gli operatori logici di Python hanno un comportamento interessante: possono lavorare con qualsiasi valore, non solo con True e False. Comprendere questo comportamento ti aiuta a scrivere codice più conciso ed evitare errori comuni.

9.4.1) Comprendere truthiness e falsiness (ripasso)

Come abbiamo imparato nel Capitolo 7, Python tratta molti valori non booleani come “truthy” o “falsy” nei contesti booleani:

Valori falsy (trattati come False):

  • False
  • None
  • 0 (zero di qualsiasi tipo numerico)
  • "" (stringa vuota)
  • [] (lista vuota)
  • {} (dizionario vuoto)
  • () (tupla vuota)

Valori truthy (trattati come True):

  • True
  • Qualsiasi numero diverso da zero
  • Qualsiasi stringa non vuota
  • Qualsiasi collezione non vuota
python
# Dimostrare la truthiness
if "hello":
    print("Le stringhe non vuote sono truthy")  # Output: Non-empty strings are truthy
 
if 0:
    print("Questo non verrà stampato")  # Zero è falsy
else:
    print("Zero è falsy")  # Output: Zero is falsy
 
if [1, 2, 3]:
    print("Le liste non vuote sono truthy")  # Output: Non-empty lists are truthy

9.4.2) Cosa restituisce davvero and

L’operatore and non restituisce sempre True o False. Invece, restituisce uno dei suoi operandi:

  • Se l’operando sinistro è falsy, and restituisce l’operando sinistro (senza valutare il destro)
  • Se l’operando sinistro è truthy, and restituisce l’operando destro
python
# and restituisce il primo valore falsy, oppure l'ultimo valore se tutti sono truthy
result = 5 and 10
print(result)  # Output: 10
 
result = 0 and 10
print(result)  # Output: 0
 
result = "hello" and "world"
print(result)  # Output: world
 
result = "" and "world"
print(result)  # Output: (empty string)
 
result = None and "world"
print(result)  # Output: None

Tracciamo questi esempi passo dopo passo:

python
# Esempio 1: Entrambi truthy
result = 5 and 10
# Step 1: 5 è truthy, quindi valuta il lato destro
# Step 2: Restituisci il valore del lato destro: 10
print(result)  # Output: 10
 
# Esempio 2: Il sinistro è falsy
result = 0 and 10
# Step 1: 0 è falsy, quindi restituiscilo immediatamente
# Step 2: Non valutare il lato destro
print(result)  # Output: 0
 
# Esempio 3: Entrambe stringhe truthy
result = "hello" and "world"
# Step 1: "hello" è truthy, quindi valuta il lato destro
# Step 2: Restituisci il valore del lato destro: "world"
print(result)  # Output: world

9.4.3) Cosa restituisce davvero or

Allo stesso modo, l’operatore or restituisce uno dei suoi operandi:

  • Se l’operando sinistro è truthy, or restituisce l’operando sinistro (senza valutare il destro)
  • Se l’operando sinistro è falsy, or restituisce l’operando destro
python
# or restituisce il primo valore truthy, oppure l'ultimo valore se tutti sono falsy
result = 5 or 10
print(result)  # Output: 5
 
result = 0 or 10
print(result)  # Output: 10
 
result = "" or "default"
print(result)  # Output: default
 
result = "hello" or "world"
print(result)  # Output: hello
 
result = None or 0
print(result)  # Output: 0

Tracciamo questi esempi:

python
# Esempio 1: Il sinistro è truthy
result = 5 or 10
# Step 1: 5 è truthy, quindi restituiscilo immediatamente
# Step 2: Non valutare il lato destro
print(result)  # Output: 5
 
# Esempio 2: Il sinistro è falsy
result = 0 or 10
# Step 1: 0 è falsy, quindi valuta il lato destro
# Step 2: Restituisci il valore del lato destro: 10
print(result)  # Output: 10
 
# Esempio 3: Entrambi falsy
result = None or 0
# Step 1: None è falsy, quindi valuta il lato destro
# Step 2: Restituisci il valore del lato destro: 0 (anche se è anch'esso falsy)
print(result)  # Output: 0

9.4.4) Usi pratici di or per valori predefiniti

Un pattern comune è usare or per fornire valori predefiniti:

python
# Preferenze utente con valori predefiniti
user_theme = ""  # L'utente non ha impostato un tema
theme = user_theme or "light"
print(f"Theme: {theme}")  # Output: Theme: light
 
user_theme = "dark"
theme = user_theme or "light"
print(f"Theme: {theme}")  # Output: Theme: dark
 
# Valori di configurazione
max_retries = None  # Non configurato
retries = max_retries or 3
print(f"Retries: {retries}")  # Output: Retries: 3
 
max_retries = 5
retries = max_retries or 3
print(f"Retries: {retries}")  # Output: Retries: 5

Questo pattern funziona perché se il lato sinistro è falsy (stringa vuota, None, 0, ecc.), or restituisce il lato destro (il valore predefinito).

and

or

No

No

Operatore logico con valore non booleano

Tipo di operatore

Lato sinistro falsy?

Lato sinistro truthy?

Restituisci il valore sinistro

Restituisci il valore destro

Restituisci il valore sinistro

Restituisci il valore destro

9.4.12) Riepilogo di cosa restituiscono gli operatori

Ecco un riepilogo completo di cosa restituisce ciascun operatore logico:

Operatore and:

  • Restituisce il primo operando falsy
  • Se tutti gli operandi sono truthy, restituisce l’ultimo operando
  • Usa la valutazione short-circuit (si ferma al primo valore falsy)

Operatore or:

  • Restituisce il primo operando truthy
  • Se tutti gli operandi sono falsy, restituisce l’ultimo operando
  • Usa la valutazione short-circuit (si ferma al primo valore truthy)

Operatore not:

  • Restituisce sempre un booleano (True o False)
  • not converte l’operando in un booleano, poi lo nega
python
# Dimostrare tutti e tre gli operatori
print(5 and 10)           # Output: 10 (both truthy, return last)
print(0 and 10)           # Output: 0 (first falsy, return it)
print(5 or 10)            # Output: 5 (first truthy, return it)
print(0 or 10)            # Output: 10 (first falsy, evaluate second)
print(not 5)              # Output: False (5 is truthy, not returns boolean)
print(not 0)              # Output: True (0 is falsy, not returns boolean)
print(not "")             # Output: True (empty string is falsy)
print(not "hello")        # Output: False (non-empty string is truthy)

Comprendere questi comportamenti ti aiuta a scrivere codice più conciso e più “Pythonic”, ma dai sempre priorità alla chiarezza. Se usare queste funzionalità rende il tuo codice più difficile da capire, è meglio essere espliciti.


In questo capitolo, abbiamo esplorato come combinare condizioni semplici in logica booleana complessa usando gli operatori and, or e not di Python. Abbiamo imparato la precedenza degli operatori, la valutazione short-circuit e il comportamento sorprendente degli operatori logici con valori non booleani. Abbiamo anche esaminato insidie comuni e best practice per scrivere espressioni booleane chiare e corrette.

Questi strumenti ti permettono di esprimere una logica decisionale sofisticata nei tuoi programmi. In combinazione con le istruzioni if del Capitolo 8, ora puoi gestire praticamente qualsiasi logica condizionale richiesta dai tuoi programmi. Nel prossimo capitolo, esploreremo le espressioni condizionali, che forniscono un modo compatto per scegliere tra due valori in base a una condizione.


© 2025. Primesoft Co., Ltd.
support@primesoft.ai