Esercizi Decoratori Python
Migliora la tua comprensione e abilità nell’uso dei decoratori in Python con questi esercizi pratici.
Esercizio 1
Scrivere un decoratore che stampa il nome della funzione chiamata.
def debug(func): def wrapper(*args, **kwargs): print(f"Chiamata funzione: {func.__name__}") return func(*args, **kwargs) return wrapper
@debugdef saluta(nome): print(f"Ciao {nome}!")
saluta("Alice")
Esercizio 2
Creare un decoratore che misura il tempo di esecuzione di una funzione.
import time
def timer(func): def wrapper(*args, **kwargs): start_time = time.time() result = func(*args, **kwargs) end_time = time.time() print(f"Tempo di esecuzione: {end_time - start_time} secondi.") return result return wrapper
@timerdef calcola(): sum([i**2 for i in range(10000)])
calcola()
Esercizio 3
Implementare un decoratore che converte l'output di una funzione in maiuscolo.
def uppercase(func): def wrapper(*args, **kwargs): original_result = func(*args, **kwargs) modified_result = original_result.upper() return modified_result return wrapper
@uppercasedef messaggio(): return 'ciao mondo'
print(messaggio())
Esercizio 4
Scrivere un decoratore che controlla se l'input di una funzione è non negativo.
def check_non_negative(func): def wrapper(*args, **kwargs): if any(arg < 0 for arg in args if isinstance(arg, (int, float))): raise ValueError("Input non può essere negativo.") return func(*args, **kwargs) return wrapper
@check_non_negativedef aggiungi(a, b): return a + b
print(aggiungi(5, 3))
Esercizio 5
Creare un decoratore che logga gli argomenti passati a una funzione.
def logger(func): def wrapper(*args, **kwargs): print(f"Chiamata a {func.__name__} con args={args} kwargs={kwargs}") return func(*args, **kwargs) return wrapper
@loggerdef somma(x, y): return x + y
somma(5, 4)
Esercizio 6
Implementare un decoratore che memorizza (cache) il risultato di una funzione per ridurre il tempo di calcolo su chiamate successive con gli stessi argomenti.
def memoize(func): cache = {} def wrapper(*args): if args in cache: return cache[args] result = func(*args) cache[args] = result return result return wrapper
@memoizedef fib(n): if n < 2: return n return fib(n-1) + fib(n-2)
print(fib(30))
Esercizio 7
Creare un decoratore che limita il numero di volte che una funzione può essere chiamata.
def limit_calls(num_calls): def decorator(func): calls = 0 def wrapper(*args, **kwargs): nonlocal calls if calls >= num_calls: raise Exception("Numero massimo di chiamate superato") calls += 1 return func(*args, **kwargs) return wrapper return decorator
@limit_calls(3)def saluta(): print("Ciao!")
saluta()saluta()saluta()saluta()
Esercizio 8
Implementare un decoratore `@authenticate` che richiede una password prima di eseguire la funzione decorata.
def authenticate(password): def decorator(func): def wrapper(*args, **kwargs): pw = input("Inserisci la password: ") if pw == password: return func(*args, **kwargs) else: print("Password errata!") return wrapper return decorator
@authenticate("s3cr3t")def segreto(): print("Questo è un messaggio segreto.")
segreto()
Esercizio 9
Scrivere un decoratore `@type_check` che assicura che gli argomenti passati a una funzione corrispondano ai tipi attesi.
def type_check(correct_type): def decorator(func): def wrapper(arg): if not isinstance(arg, correct_type): raise TypeError(f"Argomento deve essere di tipo {correct_type.__name__}") return func(arg) return wrapper return decorator
@type_check(int)def quadrato(numero): return numero ** 2
print(quadrato(5))quadrato('test')
Esercizio 10
Implementare un decoratore che ripete l'esecuzione di una funzione decorata per un numero specificato di volte.
def repeat(num_times): def decorator(func): def wrapper(*args, **kwargs): for _ in range(num_times): result = func(*args, **kwargs) return result return wrapper return decorator
@repeat(4)def saluta(nome): print(f"Ciao {nome}!")
saluta("Alice")