4 – Funzioni
Obiettivi
-
Capire che cos’è una funzione e quando usarla.
-
Creare funzioni con parametri e valori di ritorno.
-
Usare funzioni anonime (
lambda). -
Comprendere lo scope delle variabili (locale vs globale).
-
Realizzare una funzione che calcoli il fattoriale (diverse implementazioni) con esempi eseguibili.
1. Che cos’è una funzione
Una funzione è un blocco di codice riutilizzabile che esegue un compito specifico. Favorisce modularità, leggibilità e riuso.
def saluta():
print("Ciao!")
Chiamare la funzione:
saluta() # output: Ciao!
2. Creazione di funzioni: sintassi di base
def nome_funzione(param1, param2):
"""
Docstring: descrizione breve della funzione.
"""
risultato = param1 + param2
return risultato
Esempio:
def somma(a, b):
return a + b
print(somma(3, 5)) # 8
3. Parametri: tipi e comportamento
Parametri posizionali
def moltiplica(a, b):
return a * b
print(moltiplica(4, 5)) # 20
Parametri con valore di default
def saluto(nome="Amico"):
return f"Ciao, {nome}!"
print(saluto()) # Ciao, Amico!
print(saluto("Luca")) # Ciao, Luca!
Parametri keyword (nominali)
def concat(a, b):
return f"{a}-{b}"
print(concat(b="mondo", a="ciao")) # ciao-mondo
Parametri variabili: *args e **kwargs
def somma_tutti(*args):
return sum(args)
print(somma_tutti(1,2,3,4)) # 10
def stampa_info(**kwargs):
for k, v in kwargs.items():
print(k, "=", v)
stampa_info(nome="Anna", eta=30)
# nome = Anna
# eta = 30
4. Valori di ritorno multipli
In Python è possibile restituire una tupla.
def quoziente_resto(a, b):
q = a // b
r = a % b
return q, r
q, r = quoziente_resto(17, 5)
print(q, r) # 3 2
5. Funzioni anonime (lambda)
Le lambda sono funzioni in una riga, utili per funzioni semplici o come argomenti.
doppio = lambda x: x * 2
print(doppio(5)) # 10
# usata con map
nums = [1, 2, 3, 4]
dopp = list(map(lambda x: x*2, nums))
print(dopp) # [2,4,6,8]
Nota: per operazioni complesse preferire def con nome e docstring.
6. Scope delle variabili: locale vs globale
-
Variabile locale: definita dentro la funzione, visibile solo lì.
-
Variabile globale: definita fuori; accessibile in lettura dentro la funzione, ma per modificarla serve
global.
Esempi:
x = 10 # globale
def leggi():
print(x) # 10 - lettura consentita
def modifica():
global x
x = 20 # modifica la variabile globale
leggi()
modifica()
leggi() # ora stampa 20
Meglio evitare l'eccesso di variabili globali: preferire parametri e valori di ritorno.
7. Docstring e typing hints (buone pratiche)
def area_rettangolo(base: float, altezza: float) -> float:
"""Restituisce l'area di un rettangolo."""
return base * altezza
print(area_rettangolo(3.5, 2)) # 7.0
Le annotazioni : float e -> float sono consigliate per leggibilità e supporto editoriale, ma non sono obbligatorie.
8. Esempi pratici: funzioni utili
Validazione email (semplice)
import re
def is_email(s: str) -> bool:
pattern = r'^\S+@\S+\.\S+$'
return bool(re.match(pattern, s))
print(is_email("luca@example.com")) # True
print(is_email("notaemail")) # False
Funzione ricorsiva: potenza
def potenza(base: float, esp: int) -> float:
if esp == 0:
return 1
elif esp > 0:
return base * potenza(base, esp - 1)
else:
return 1 / potenza(base, -esp)
9. Esercizio principale: funzione che calcola il fattoriale
Descrizione: calcolare n! = n × (n-1) × ... × 1 per interi non negativi n. Definire più implementazioni e mostrare esempi numerici.
9.1 Fattoriale iterativo (raccomandato per produzione)
def factorial_iter(n: int) -> int:
"""
Calcola il fattoriale in modo iterativo.
Solleva ValueError per n < 0.
"""
if n < 0:
raise ValueError("n deve essere >= 0")
result = 1
for i in range(2, n+1):
result *= i
return result
# Esempi
print(factorial_iter(0)) # 1
print(factorial_iter(1)) # 1
print(factorial_iter(5)) # 120
print(factorial_iter(10)) # 3628800
9.2 Fattoriale ricorsivo (più elegante, attenzione allo stack)
def factorial_rec(n: int) -> int:
if n < 0:
raise ValueError("n deve essere >= 0")
if n == 0 or n == 1:
return 1
return n * factorial_rec(n - 1)
# Test
print(factorial_rec(6)) # 720
9.3 Fattoriale usando math.factorial
import math
print(math.factorial(7)) # 5040
9.4 Controllo dimensionale / controllo input
Assicurati sempre che l'input sia un intero non negativo:
def factorial_safe(x):
if not isinstance(x, int):
raise TypeError("Il valore deve essere un intero")
return factorial_iter(x)
Esempio completo con gestione eccezioni:
try:
print(factorial_safe(5)) # 120
print(factorial_safe(-1)) # solleva ValueError
except Exception as e:
print("Errore:", e)
10. Esercizi proposti (con soluzioni sintetiche indicate)
-
Scrivi una funzione
is_prime(n)che ritornaTruesenè primo.-
Suggerimento: controlla i divisori fino a sqrt(n).
-
-
Scrivi una funzione
gcd(a, b)(Massimo Comune Divisore) usando l'algoritmo di Euclide.def gcd(a, b): while b: a, b = b, a % b return abs(a) -
Scrivi
factorial_tail(n, acc=1)versione ricorsiva in coda (tail recursion). Nota: Python non ottimizza la tail recursion, ma è un buon esercizio concettuale. -
Scrivi una funzione
apply_twice(f, x)che applica la funzionefdue volte ax. Usalambdaper test.def apply_twice(f, x): return f(f(x)) print(apply_twice(lambda y: y+3, 4)) # 10
11. Note finali e best practice
-
Preferire implementazioni iterative per problemi come il fattoriale se la profondità di ricorsione può essere grande.
-
Documenta ogni funzione con docstring e fornisci esempi di utilizzo.
-
Usa typing hints per chiarezza.
-
Evita di modificare variabili globali all'interno delle funzioni: preferisci parametri e ritorni.
-
Scrivi test semplici (assert) per verificare il comportamento atteso.

Nessun commento:
Posta un commento