- Home
- iThink
- Programmazione per Ragazzi
- Funzioni in Python: scriverle, chiamarle, riusarle
Funzioni in Python: scriverle, chiamarle, riusarle
Divento Programmatore — Capitolo 4: Funzioni
Hai scritto codice che decide (Cap. 3) e ripete (cicli). Ora impari a incapsulare logica in blocchi riutilizzabili: le funzioni. È il salto da "script" a "programma vero".
Cosa imparerai
| Concetto | Descrizione | | ---------- | ------------- | | def | Parola chiave per definire una funzione | | Parametri | Input della funzione (placeholders) | | Argomenti | Valori reali passati alla chiamata | | return | Output: restituisce valore al chiamante | | Scope | Dove le variabili "vivono" (locale vs globale) | | Docstring | Documentazione integrata ("""...""") | | DRY | Don't Repeat Yourself — principio chiave |
1. Perché le funzioni? L'analogia della ricetta
Una ricetta dice: "Prendi ingredienti, fai passi, ottieni piatto". La usi quante volte vuoi.
# SENZA funzione (ripetizione = male)
print("=== MENU ===")
print("1. Pizza")
print("2. Pasta")
print("3. Insalata")
print("==============")
# ... 50 righe dopo ...
print("=== MENU ===")
print("1. Pizza")
print("2. Pasta")
print("3. Insalata")
print("==============")
# CON funzione (DRY = bene)
def mostra_menu():
print("=== MENU ===")
print("1. Pizza")
print("2. Pasta")
print("3. Insalata")
print("==============")
mostra_menu() # Chiama la funzione
# ... 50 righe dopo ...
mostra_menu() # Riutilizza!
Regola d'oro: Se copi-incolli codice → trasformalo in funzione.
2. Anatomia di una funzione
def saluta(nome: str) -> str:
"""Restituisce un saluto personalizzato.
Args:
nome: Nome della persona da salutare.
Returns:
Stringa di saluto formattata.
"""
messaggio = f"Ciao, {nome}!" # Variabile LOCALE
return messaggio # Esce e restituisce valore
# Uso
risultato = saluta("Alex")
print(risultato) # Ciao, Alex!
Parti obbligatorie
| Parte | Esempio | Note | | ------- | --------- | ------ | | def | def saluta( | Parola chiave | | Nome | saluta | snake_case, verbo | | Parametri | (nome: str) | Tra parentesi, opzionali | | : | ): | Due punti finali | | Corpo | messaggio = ... | Indentato 4 spazi | | return | return messaggio | Opzionale (default None) |
Type hints (opzionali ma consigliati)
def area_rettangolo(base: float, altezza: float) -> float:
return base * altezza
base: float= parametro atteso float-> float= tipo di ritorno- Non enforced a runtime, ma aiutano editor e lettori
3. Parametri e argomenti
Posizionali (ordine conta)
def presenta(nome, eta, citta):
print(f"{nome}, {eta} anni, da {citta}")
presenta("Luna", 13, "Roma") # OK
presenta("Roma", 13, "Luna") # Logica sbagliata, ma sintassi OK
Named (keyword arguments) — ordine NON conta
presenta(nome="Luna", citta="Roma", eta=13)
presenta(citta="Roma", nome="Luna", eta=13) # Uguale
Valori di default (parametri opzionali)
def saluta(nome, saluto="Ciao"):
print(f"{saluto}, {nome}!")
saluta("Alex") # Ciao, Alex!
saluta("Alex", "Ehi") # Ehi, Alex!
saluta(nome="Sam") # Ciao, Sam!
saluta(saluto="Hey", nome="Sam") # Hey, Sam!
Regola: Parametri con default dopo quelli senza.
# OK
def f(a, b=1, c=2): pass
# ERRORE
def f(a=1, b): pass # SyntaxError
*args e **kwargs (anticipazione avanzata)
def somma(*numeri): # Tupla di positional args
return sum(numeri)
def configura(**opzioni): # Dizionario di keyword args
for k, v in opzioni.items():
print(f"{k} = {v}")
somma(1, 2, 3, 4) # 10
configura(volume=80, fullscreen=True, difficulty="hard")
4. Return: restituire valori
def quadrato(x):
return x * x
risultato = quadrato(5) # risultato = 25
print(quadrato(7)) # Stampa 49 direttamente
Return multipli (tupla)
def min_max(lista):
return min(lista), max(lista)
minimo, massimo = min_max([3, 1, 4, 1, 5])
print(minimo, massimo) # 1 5
Return anticipato (guard clause)
def dividi(a, b):
if b == 0:
return None # Esce subito, evita errore
return a / b
Funzioni senza return → restituiscono None
def stampa_due_volte(testo):
print(testo)
print(testo)
risultato = stampa_due_volte("Hey")
print(risultato) # None
5. Scope: dove vivono le variabili
Locale (dentro funzione)
def foo():
x = 10 # Locale a foo()
print(x)
foo() # 10
print(x) # NameError! x non esiste qui
Globale (fuori funzioni)
GIOCATORE = "Alex" # Globale (convenzione: MAIUSCOLO)
def saluta():
print(GIOCATORE) # Legge globale OK
saluta() # Alex
Modificare globale (serve global)
punteggio = 0
def aggiungi_punti(p):
global punteggio
punteggio += p
aggiungi_punti(10)
print(punteggio) # 10
Best practice: Evita
global. Passa valori come parametri, restituisci risultati. Funzioni pure = stesso input → stesso output, niente effetti collaterali.
Shadowing (variabile locale nasconde globale)
nome = "Globale"
def test():
nome = "Locale" # Nuova variabile locale
print(nome) # Locale
test() # Locale
print(nome) # Globale (invariata)
6. Docstring: documenta le tue funzioni
def calcola_danno(attacco: int, difesa: int, critico: bool = False) -> int:
"""Calcola danno finale considerando attacco, difesa e critico.
Formula: max(1, attacco - difesa) * (2 se critico else 1)
Args:
attacco: Valore attacco attaccante (>= 0).
difesa: Valore difesa bersaglio (>= 0).
critico: True se colpo critico (default False).
Returns:
Danno intero >= 1.
Esempio:
>>> calcola_danno(10, 3, True)
14
"""
base = max(1, attacco - difesa)
return base * (2 if critico else 1)
Formato consigliato: Google Style o NumPy. Thonny mostra docstring con Ctrl+Shift+Spazio o hover.
7. Funzioni come "ricette" per i giochi
Esempio: sistema combattimento
import random
def tira_dado(facce: int = 6) -> int:
"""Simula lancio dado."""
return random.randint(1, facce)
def calcola_colpo(attacco: int, precisione: int) -> bool:
"""True se colpo va a segno."""
tiro = tira_dado(20)
return tiro <= precisione
def calcola_danno(base: int, arma: str) -> int:
"""Danno base + bonus arma."""
bonus = {"spada": 3, "ascia": 5, "arco": 2, "pugnale": 1}
return base + bonus.get(arma, 0)
def attacca(nome: str, attacco: int, precisione: int, arma: str) -> str:
"""Esegue un attacco e restituisce messaggio."""
if calcola_colpo(attacco, precisione):
dmg = calcola_danno(attacco, arma)
return f"🎯 {nome} colpisce con {arma}! Danno: {dmg}"
else:
return f"💨 {nome} manca il bersaglio!"
# Uso
print(attacca("Guerriero", 12, 14, "spada"))
print(attacca("Arciere", 10, 16, "arco"))
8. Script completo: Calcolatrice modulare
# calcolatrice.py
"""Calcolatrice a funzioni: ogni operazione è una funzione."""
def somma(a: float, b: float) -> float:
return a + b
def differenza(a: float, b: float) -> float:
return a - b
def prodotto(a: float, b: float) -> float:
return a * b
def divisione(a: float, b: float) -> float | None:
if b == 0:
return None
return a / b
def potenza(a: float, b: float) -> float:
return a ** b
OPERAZIONI = {
"1": ("Somma", somma, "+"),
"2": ("Differenza", differenza, "-"),
"3": ("Prodotto", prodotto, "*"),
"4": ("Divisione", divisione, "/"),
"5": ("Potenza", potenza, "**"),
}
def menu() -> str:
print("\n=== CALCOLATRICE ===")
for k, (nome, _, _) in OPERAZIONI.items():
print(f"{k}. {nome}")
print("0. Esci")
return input("Scegli: ")
def main():
while True:
scelta = menu()
if scelta == "0":
print("Arrivederci!")
break
if scelta not in OPERAZIONI:
print("Opzione non valida.")
continue
nome, func, simbolo = OPERAZIONI[scelta]
try:
a = float(input("Primo numero: "))
b = float(input("Secondo numero: "))
except ValueError:
print("Inserisci numeri validi.")
continue
risultato = func(a, b)
if risultato is None:
print("Errore: divisione per zero!")
else:
print(f"Risultato: {a} {simbolo} {b} = {risultato}")
if __name__ == "__main__":
main()
Nuovo pattern: if __name__ == "__main__": — il codice sotto gira solo se esegui il file direttamente, non se lo importi. Fondamentale per moduli (Cap. 6).
9. Tabella riassuntiva: checklist funzione ben fatta
| ✅ Controllo | Descrizione | | -------------- | ------------- | | Nome verbo | calcola_, ottieni_, valida_, disegna_ | | Un compito solo | Funzione fa UNA cosa bene | | Parametri tipizzati | def f(x: int) -> bool: | | Docstring | Cosa fa, args, return, esempio | | No side effects | Non modifica globali, non stampa (salvo funzioni I/O) | | Return esplicito | return valore non return nudo | | Testabile | Stesso input → stesso output |
10. Esercizi pratici
- Fattoriale:
def fattoriale(n: int) -> int:(ricorsivo o iterativo) - Primo:
def e_primo(n: int) -> bool: - Password generator:
def genera_password(lunghezza: int = 12) -> str: - Validazione email:
def email_valida(email: str) -> bool:(usa@e.) - Refactoring: Prendi script Cap. 3 (Indovina numero) e spezza in funzioni:
gioca_partita(),chiedi_numero(),dai_hint()
11. Checklist fine capitolo
- [ ] Scrivi
def nome_funzione(parametri) -> tipo: - [ ] Usi parametri posizionali, named, e con default
- [ ] Restituisci valori con
return - [ ] Capisci scope locale vs globale (evita
global) - [ ] Scrivi docstring Google/NumPy style
- [ ] Applichi DRY: nessuna copia-incolla di logica
- [ ] Conosci
if __name__ == "__main__":
Prossimo capitolo
Capitolo 5: Liste e dizionari — Collezioni di dati: ordinate (liste) e chiave-valore (dizionari). Operazioni, indexing, slicing, metodi, nesting, loop su collezioni.
Serie "Divento Programmatore: Python e i Giochi" (Cervello Elettronico Vol.2). Codice completo, tabelle, esercizi. Target 10-14 anni + guide adulti.