Come usare i decoratori Python per migliorare le funzioni
I decoratori Python sono un modo potente e flessibile per modificare o migliorare funzioni e metodi. I decoratori forniscono un modo per avvolgere una funzione con funzionalità aggiuntive, consentendo di estendere il suo comportamento senza modificarne il codice effettivo. Questo articolo ti introdurrà al concetto di decoratori, a come crearli e usarli e ad esplorare alcuni esempi pratici.
Che cosa è un decoratore?
Un decoratore è una funzione che prende un'altra funzione e ne estende il comportamento senza modificarla esplicitamente. In Python, i decoratori sono spesso utilizzati per aggiungere funzionalità come la registrazione, il controllo degli accessi o la misurazione delle prestazioni a funzioni o metodi esistenti. I decoratori vengono applicati alle funzioni utilizzando la sintassi @decorator_name
.
# Basic example of a decorator
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
Come lavorano i decoratori
Quando si applica un decoratore a una funzione, Python esegue essenzialmente i seguenti passaggi:
- La funzione decoratrice viene chiamata con la funzione originale come argomento.
- La funzione decoratore definisce una nuova funzione (spesso chiamata
wrapper
) che migliora o modifica il comportamento della funzione originale. - La funzione decoratore restituisce la nuova funzione.
- Quando viene chiamata la funzione decorata, in realtà chiama la nuova funzione restituita dal decoratore.
Creare un semplice decoratore
Creiamo un semplice decoratore che misuri il tempo di esecuzione di una funzione. È utile per i test delle prestazioni e l'ottimizzazione.
import time
def timing_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"Execution time: {end_time - start_time} seconds")
return result
return wrapper
@timing_decorator
def slow_function():
time.sleep(2)
print("Function finished!")
slow_function()
Utilizzo dei decoratori con argomenti
A volte, potresti voler passare argomenti al tuo decoratore. Per ottenere questo, devi creare una fabbrica di decoratori, una funzione che restituisce un decoratore. Ecco un esempio di un decoratore che accetta un argomento per specificare un messaggio personalizzato.
def custom_message_decorator(message):
def decorator(func):
def wrapper(*args, **kwargs):
print(message)
return func(*args, **kwargs)
return wrapper
return decorator
@custom_message_decorator("Starting the function...")
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
Decoratori per metodi nelle classi
I decoratori possono anche essere usati con metodi all'interno delle classi. Gli usi comuni includono la registrazione delle chiamate di metodo, il controllo degli accessi e la memorizzazione nella cache dei risultati. Ecco un esempio di utilizzo di un decoratore per registrare le chiamate di metodo in una classe.
def log_method_call(method):
def wrapper(self, *args, **kwargs):
print(f"Calling {method.__name__} with arguments {args} and keyword arguments {kwargs}")
return method(self, *args, **kwargs)
return wrapper
class MyClass:
@log_method_call
def my_method(self, x, y):
print(f"Result: {x + y}")
obj = MyClass()
obj.my_method(5, 7)
Decoratori a catena
È possibile applicare più decoratori a una singola funzione. Vengono applicati dal decoratore più interno a quello più esterno. Ciò consente di comporre diverse funzionalità insieme. Ecco un esempio di concatenamento di due decoratori:
def uppercase_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result.upper()
return wrapper
def exclamation_decorator(func):
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
return result + "!"
return wrapper
@exclamation_decorator
@uppercase_decorator
def greet(name):
return f"Hello, {name}"
print(greet("Alice"))
Conclusione
I decoratori sono uno strumento versatile in Python che consente di migliorare o modificare il comportamento di funzioni e metodi. Utilizzando i decoratori, è possibile aggiungere funzionalità riutilizzabili nel codice di base senza modificare la logica di base delle funzioni. Che si tratti di registrazione, temporizzazione o modifica dell'output, i decoratori aiutano a mantenere il codice pulito e gestibile. Fai pratica utilizzando i decoratori per diventare più competente e sfruttare la loro potenza nei progetti Python.