1. Home
  2. iThink
  3. Programmazione per Ragazzi
  4. Calcolatrice parlante in Python con le funzioni
Programmazione per Ragazzi Divento Programmatore · Capitolo 4

Calcolatrice parlante in Python con le funzioni

Codice Python sullo schermo di un computer
Foto: JohnsonMartin · Pixabay · Licenza dei contenuti Pixabay

Divento Programmatore — Capitolo 4: Calcolatrice Parlante

Obiettivi di Apprendimento

Al termine di questo capitolo avrai costruito una Calcolatrice Parlante e imparerai a:

  • Definire e utilizzare le funzioni (def) per strutturare e riutilizzare il codice
  • Passare argomenti e ricevere valori di ritorno (return) dalle funzioni
  • Gestire gli errori dell'utente con try e except per prevenire i crash del programma
  • Catturare eccezioni specifiche come ValueError e ZeroDivisionError
  • Utilizzare variabili globali per mantenere uno stato di memoria persistente

Termini Fondamentali

| Termine | Simbolo | Significato | | --------- | --------- | ------------- | | Funzione (function) | 🤖 | Blocco di codice riutilizzabile identificato da un nome, progettato per svolgere un compito specifico | | Parametro / Argomento (parameter / argument) | 📥 | L'informazione che passi a una funzione come input per permetterle di lavorare | | Valore di Ritorno (return value) | 📤 | Il risultato finale che una funzione restituisce al programma principale al termine della sua esecuzione | | Eccezione (exception) | ⚠️ | Un errore che si verifica durante l'esecuzione del programma e che lo blocca se non viene gestito correttamente | | try / except | 🛡️ | Blocco di codice usato in Python per catturare e gestire le eccezioni in modo sicuro | | Overflow | 📈 | Errore che si verifica quando un calcolo produce un numero troppo grande per essere gestito dalla memoria del computer |


La Storia: La calcolatrice nello spazio

Prima degli smartphone e dei computer portatili, gli scienziati e gli ingegneri dovevano eseguire tutti i calcoli a mano, su fogli di carta o usando uno strumento chiamato regolo calcolatore. Negli anni '60, per spedire gli astronauti sulla Luna, la NASA dovette impiegare centinaia di persone (chiamate letteralmente "computer umani") che calcolavano le traiettorie delle navicelle spaziali ore dopo ore.

Tutto cambiò nel 1974, quando la Hewlett-Packard presentò la HP-65, la prima calcolatrice tascabile programmabile al mondo. Non solo calcolava addizioni e sottrazioni, ma consentiva agli utenti di scrivere piccoli programmi memorizzati su minuscole schede magnetiche. La HP-65 era così potente e affidabile che gli astronauti della missione Apollo-Soyuz la portarono nello spazio come computer di riserva per calcolare la rotta di rientro sulla Terra in caso di guasto al computer di bordo!

Oggi, ogni computer esegue miliardi di calcoli al secondo. Ma per farlo senza bloccarsi (andare in crash) ogni volta che l'utente commette un errore di battitura, ha bisogno di codice robusto. In questo capitolo imparerai a scrivere funzioni matematiche solide e a blindare il codice dai crash improvvisi!


Concept 1: Le Funzioni (I tuoi piccoli robot di fiducia)

Immagina di avere in cucina un frullatore. Ogni volta che vuoi un frullato, non devi smontare e rimontare il motore del frullatore: versi gli ingredienti (gli argomenti), premi il pulsante di accensione (chiami la funzione) e ottieni il frullato pronto (il valore di ritorno).

In programmazione, le funzioni funzionano esattamente così. Servono a raggruppare un pezzo di codice e a dargli un nome, così da poterlo riutilizzare quando vuoi senza riscriverlo da capo.

In Python, una funzione si definisce usando la parola chiave def:

def saluta_giocatore(nome):  # "nome" è il parametro di input
    messaggio = f"Ciao {nome}! Pronto a calcolare?"
    return messaggio  # Restituiamo il valore al programma principale

Per chiamare e usare la funzione, scrivi il suo nome passandole il valore desiderato:

saluto = saluta_giocatore("Leo")
print(saluto)  # Mostra a schermo: Ciao Leo! Pronto a calcolare?

Le regole d'oro delle funzioni:

  • Usano la parola chiave def seguita dal nome e dalle parentesi tonde ()
  • I parametri (se presenti) vanno scritti all'interno delle parentesi
  • Il codice della funzione deve essere rientrato (indentato)
  • La parola chiave return restituisce il risultato e interrompe immediatamente l'esecuzione della funzione

Concept 2: La Gestione degli Errori (Il paracadute del codice)

Cosa succede se il tuo programma si aspetta che l'utente inserisca un numero intero e questo digita la parola "cinque"? Oppure cosa accade se prova a dividere un numero per 0? Python si spaventa, interrompe l'esecuzione e mostra una sfilza di scritte rosse a schermo (un crash del programma).

Per evitare questo disastro, i programmatori usano il costrutto try (prova) e except (eccetto/gestisci).

try:
    numero = int(input("Inserisci un numero: "))
    print(f"Ottimo! Il doppio è {numero * 2}")
except ValueError:
    print("Ehi! Ti ho chiesto un numero, non delle lettere!")

Come funziona questo blocco?

  1. Python esegue il codice dentro il blocco try.
  2. Se tutto va bene, ignora il blocco except.
  3. Se durante l'esecuzione del try si verifica un errore di tipo ValueError (valore non valido), Python interrompe subito quel blocco e salta direttamente all'interno dell'istruzione except per eseguire il codice di rimedio. Il programma non va in crash e continua a girare felice!

Costruiamo il Gioco: Versione Base

Ecco la versione base di una calcolatrice testuale strutturata con funzioni e ciclo principale:

def somma(a, b):
    return a + b

def sottrazione(a, b):
    return a - b

def moltiplicazione(a, b):
    return a * b

def divisione(a, b):
    return a / b

print("🤖 BENVENUTO ALLA CALCOLATRICE BASE 🤖\n")

num1 = float(input("Inserisci il primo numero: "))
num2 = float(input("Inserisci il secondo numero: "))

print("\nSeleziona l'operazione:")
print("1. Somma (+)")
print("2. Sottrazione (-)")
print("3. Moltiplicazione (*)")
print("4. Divisione (/)")

scelta = input("Scegli (1-4): ")

if scelta == "1":
    print("Risultato:", somma(num1, num2))
elif scelta == "2":
    print("Risultato:", sottrazione(num1, num2))
elif scelta == "3":
    print("Risultato:", moltiplicazione(num1, num2))
elif scelta == "4":
    print("Risultato:", divisione(num1, num2))

Sfide: Fai salire di livello la tua Calcolatrice

Sfida 1 — Operazioni Avanzate

Aggiungiamo due nuove operazioni matematiche: l'elevamento a potenza (usando l'operatore ** di Python) e il calcolo del resto della divisione intera (usando l'operatore modulo %).

Sfida 2 — Personalità "Parlante"

Creiamo una funzione che analizzi il risultato ottenuto e stampi un commento ironico o divertente a console. La calcolatrice prenderà in giro l'utente se i numeri sono giganti, negativi o se tenta operazioni strane!

Sfida 3 — Registro delle Operazioni (Cronologia)

Utilizziamo una lista per memorizzare le ultime 5 operazioni effettuate. L'utente potrà selezionare un'opzione dal menu per consultare la cronologia dei suoi calcoli precedenti.

Sfida 4 — Funzioni di Memoria

Simuliamo il comportamento delle calcolatrici reali aggiungendo tasti di memoria:

  • MS (Memory Store): Salva il numero corrente in una variabile speciale
  • MR (Memory Recall): Richiama il numero salvato per usarlo nei calcoli
  • MC (Memory Clear): Ripristina a zero il valore memorizzato

Il Codice Completo con Tutte le Sfide

Salva questo codice in Thonny come calcolatrice_parlante.py ed eseguilo per testare la sua personalità ironica!

import sys

# Variabili di stato globali per la calcolatrice
cronologia = []
memoria = 0.0

def somma(a, b): return a + b
def sottrazione(a, b): return a - b
def moltiplicazione(a, b): return a * b

def divisione(a, b):
    if b == 0:
        raise ZeroDivisionError("Impossibile dividere per zero!")
    return a / b

def potenza(a, b): return a ** b
def resto(a, b): return a % b

def leggi_numero(messaggio):
    """Legge un numero float da tastiera, convalidando l'input."""
    while True:
        try:
            return float(input(messaggio))
        except ValueError:
            print("🤖 Ehi! Questo non mi sembra un numero. Riprova!")

def aggiungi_cronologia(operazione):
    """Mantiene in memoria gli ultimi 5 calcoli effettuati."""
    cronologia.append(operazione)
    if len(cronologia) > 5:
        cronologia.pop(0)

def commento_parlante(operazione, risultato):
    """Sfida 2: La calcolatrice commenta in base al tipo di calcolo."""
    if operazione == "/" and risultato == 0:
        return "🤖 Complimenti, hai diviso zero per qualcosa. Un calcolo davvero utile..."
    elif risultato > 9000:
        return "🤖 Wow! Questo numero è enorme! Sta quasi per fondermi i chip!"
    elif risultato < 0:
        return "🤖 Un risultato negativo? Spero che questo non rappresenti i tuoi risparmi!"
    else:
        return "🤖 Ecco il tuo risultato, pulito e preciso!"

def main():
    global memoria
    
    print("╔══════════════════════════════════════╗")
    print("║        🤖 CALCOLATRICE PARLANTE 🤖   ║")
    print("║   Gestione errori, Memoria & Humor   ║")
    print("╚══════════════════════════════════════╝")
    
    while True:
        print("\n--- MENU OPERAZIONI ---")
        print("1. Addizione (+)")
        print("2. Sottrazione (-)")
        print("3. Moltiplicazione (*)")
        print("4. Divisione (/)")
        print("5. Potenza (**)")
        print("6. Resto (%)")
        print("7. Mostra Cronologia (ultimi 5 calcoli)")
        print("8. Gestione Memoria (MS/MR/MC)")
        print("9. Spegni Calcolatrice")
        
        scelta = input("\nScegli un'opzione (1-9): ").strip()
        
        if scelta == "9":
            print("\n🤖 Ciao ciao! Vado in modalità risparmio energetico... Zzz...")
            break
            
        elif scelta == "7":
            if not cronologia:
                print("🤖 La cronologia è vuota. Fai lavorare i miei circuiti prima!")
            else:
                print("\n📋 CRONOLOGIA ULTIMI CALCOLI:")
                for idx, calc in enumerate(cronologia, 1):
                    print(f"  {idx}. {calc}")
            continue
            
        elif scelta == "8":
            print(f"\n💾 STATO MEMORIA: {memoria}")
            print("1. Salva valore in Memoria (MS)")
            print("2. Richiama valore da Memoria (MR)")
            print("3. Cancella Memoria (MC)")
            sub_scelta = input("Scegli un'operazione (1-3): ").strip()
            
            if sub_scelta == "1":
                memoria = leggi_numero("Inserisci il valore da salvare: ")
                print(f"🤖 Valore {memoria} salvato in memoria.")
            elif sub_scelta == "2":
                print(f"🤖 Valore in memoria richiamato: {memoria}")
            elif sub_scelta == "3":
                memoria = 0.0
                print("🤖 Memoria azzerata.")
            continue
            
        if scelta not in ["1", "2", "3", "4", "5", "6"]:
            print("🤖 Opzione non valida! Scegli un numero da 1 a 9.")
            continue
            
        # Lettura operandi con convalida automatica
        num1 = leggi_numero("Inserisci il primo numero: ")
        num2 = leggi_numero("Inserisci il secondo numero: ")
        
        simbolo = ""
        risultato = 0.0
        operazione_valida = True
        
        try:
            if scelta == "1":
                risultato = somma(num1, num2)
                simbolo = "+"
            elif scelta == "2":
                risultato = sottrazione(num1, num2)
                simbolo = "-"
            elif scelta == "3":
                risultato = moltiplicazione(num1, num2)
                simbolo = "*"
            elif scelta == "4":
                risultato = divisione(num1, num2)
                simbolo = "/"
            elif scelta == "5":
                risultato = potenza(num1, num2)
                simbolo = "**"
            elif scelta == "6":
                risultato = resto(num1, num2)
                simbolo = "%"
        except ZeroDivisionError:
            print("\n💥 ERRORE CRITICO DI SISTEMA!")
            print("🤖 Ehi! Non provare a distruggere l'universo dividendo per zero!")
            operazione_valida = False
        except OverflowError:
            print("\n💥 ERRORE CRITICO!")
            print("🤖 Troppo grande! I miei registri di memoria sono andati in overflow!")
            operazione_valida = False
            
        if operazione_valida:
            espressione = f"{num1} {simbolo} {num2} = {risultato}"
            aggiungi_cronologia(espressione)
            print(f"\n📊 Risultato: {risultato}")
            print(commento_parlante(simbolo, risultato))

if __name__ == "__main__":
    main()

Analisi del Codice Completo

Andiamo a scoprire i dettagli tecnici di questa calcolatrice corazzata:

1. Funzione di lettura protetta (leggi_numero)

Invece di chiamare direttamente float(input()) nel corpo principale, abbiamo creato una funzione riutilizzabile. Il ciclo while True gira all'infinito finché l'utente non inserisce un dato valido. Non appena viene inserito un numero corretto, l'istruzione return interrompe immediatamente sia il blocco try sia l'intero ciclo while, restituendo il valore a chi ha chiamato la funzione.

2. Sollevamento esplicito delle Eccezioni (raise)

Nella funzione divisione, controlliamo se il divisore b è 0. In tal caso, usiamo l'istruzione raise ZeroDivisionError(...) per l'invocazione esplicita dell'errore. Questo fa sì che il blocco try/except nel main intercetti l'errore matematico in modo pulito e stampi l'avviso ironico anziché arrestare il gioco.

3. Gestione della memoria con variabili globali

All'inizio del file definiamo memoria = 0.0. Quando vogliamo modificare questo valore dall'interno della funzione main(), dobbiamo dichiarare global memoria all'inizio della funzione. Senza questa dichiarazione, Python penserebbe che memoria sia una variabile locale temporanea creata solo dentro main e non aggiornerebbe il dato salvato all'esterno!

4. Controllo degli errori di Overflow

Se provi a calcolare una potenza enorme su numeri decimali (ad esempio 9999999.0 ** 999999), il computer va in crisi: i numeri decimali in Python hanno dimensione fissa, e quando il risultato è troppo grande Python solleverà un OverflowError. Con i numeri interi, invece, Python è più furbo: li gestisce con dimensione variabile (bignum), quindi 9999999 ** 999999 produce un risultato con milioni di cifre senza errori — ma con molta pazienza! Abbiamo inserito un blocco except OverflowError per intercettare l'errore nei calcoli in virgola mobile ed evitare il crash.


Curiosità: Il primo "bug" reale

Lo sapevi che i primi computer utilizzavano le valvole termoioniche (simili a lampadine a incandescenza) per eseguire i calcoli? Essendo calde e luminose, attiravano insetti veri. Nel 1947, la scienziata Grace Hopper trovò una falena reale incastrata tra i contatti di un relè del computer Harvard Mark II, che bloccava il calcolo. Rimosse la falena con delle pinzette e la incollò sul diario di bordo scrivendo: "Primo caso reale di bug (insetto) trovato!". Da quel giorno, correggere gli errori di codice si chiama debugging!


Provaci tu! — Nuovi commenti

Modifica la funzione commento_parlante per aggiungere un commento specifico se il risultato del calcolo è esattamente 42 (il numero che, secondo la celebre saga Guida galattica per gli autostoppisti, rappresenta la risposta alla domanda fondamentale sulla vita, l'universo e tutto quanto!).


Il Piccolo Glossario

| Termine | Definizione | | --------- | ------------- | | Function / Funzione | Un blocco di istruzioni riutilizzabili a cui viene assegnato un nome. | | Parameter / Parametro | La variabile locale che accetta i valori di input passati a una funzione. | | Return value / Valore di ritorno | Il dato finale inviato all'esterno da una funzione tramite l'istruzione return. | | Exception / Eccezione | Un evento imprevisto che si verifica durante l'esecuzione del codice (ad esempio divisione per zero o input errato). | | try/except | Costrutto utilizzato in Python per tentare l'esecuzione di un blocco e intercettare eventuali errori senza andare in crash. | | ValueError | Errore sollevato quando il tipo di un dato è corretto ma il valore non è appropriato (es: convertire "abc" in numero float). | | ZeroDivisionError | Errore sollevato quando si tenta di dividere un numero per zero. | | OverflowError | Errore sollevato quando il risultato di un calcolo in virgola mobile supera i limiti fisici della memoria. Con i numeri interi Python usa la gestione bignum, quindi questo errore non si verifica mai con gli int. | | Global variable / Variabile globale | Una variabile definita all'esterno delle funzioni, accessibile e modificabile da qualsiasi punto del codice. |


Prossimo capitolo

Capitolo 5: L'Impiccato Digitale
Stringhe immutabili, operatore in, set per lettere tentate, ASCII Art multilinea, caricamento parole.txt split(':',1), FileNotFoundError. Codice completo con 7 livelli ASCII art.


Questo post è un estratto dal libro "Divento Programmatore: Python e i Giochi" (Volume 2 della collana "Cervello Elettronico") di Rocco Balzamà. Target: 10-14 anni · ~180 pagine · Thonny + VS Code.

Per approfondire

Fonti e riferimenti

Condividi LinkedIn Facebook X WhatsApp
Continua a leggere

Tutti gli articoli del blog

Strumenti gratuiti