📢 Nuovo Corso Bootstrap Completo disponibile!

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
@debug
def 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
@timer
def 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
@uppercase
def 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_negative
def 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
@logger
def 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
@memoize
def 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")