🚀 Nuova versione beta disponibile! Feedback o problemi? Contattaci

Esercizi Decoratori Python

Codegrind Team•Jul 10 2024

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")