Context engineering
4 – Funzioni
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.
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!
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
def moltiplica(a, b):
return a * b
print(moltiplica(4, 5)) # 20
def saluto(nome="Amico"):
return f"Ciao, {nome}!"
print(saluto()) # Ciao, Amico!
print(saluto("Luca")) # Ciao, Luca!
def concat(a, b):
return f"{a}-{b}"
print(concat(b="mondo", a="ciao")) # ciao-mondo
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
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
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.
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.
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.
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
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)
Descrizione: calcolare n! = n × (n-1) × ... × 1 per interi non negativi n. Definire più implementazioni e mostrare esempi numerici.
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
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
math.factorialimport math
print(math.factorial(7)) # 5040
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)
Scrivi una funzione is_prime(n) che ritorna True se n è 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 funzione f due volte a x. Usa lambda per test.
def apply_twice(f, x):
return f(f(x))
print(apply_twice(lambda y: y+3, 4)) # 10
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.
Commenti
Posta un commento