Decoratori Python: Aggiungere Superpoteri alle Tue Funzioni
Ciao a tutti, aspiranti programmatori Python! Oggi, esploreremo il fascinante mondo dei decoratori Python. Immagina i decoratori come wrappatori magici che possono arricchire le tue funzioni con superpoteri. Entusiastico, vero? Iniziamo insieme questo viaggio!
Cos'è un Decoratore?
Immagina di avere un regalo bellissimamente avvolto. La carta da regalo non cambia il regalo stesso, ma lo rende più bello, giusto? Esattamente quello che fanno i decoratori alle tue funzioni in Python. Wrappano le tue funzioni, aggiungendo funzionalità extra senza cambiare la funzione originale.
Iniziamo con un esempio semplice:
def mio_decoratore(func):
def wrapper():
print("Qualcosa sta accadendo prima che la funzione venga chiamata.")
func()
print("Qualcosa sta accadendo dopo che la funzione è stata chiamata.")
return wrapper
@mio_decoratore
def dice_ciao():
print("Ciao!")
dice_ciao()
Se esegui questo codice, vedrai:
Qualcosa sta accadendo prima che la funzione venga chiamata.
Ciao!
Qualcosa sta accadendo dopo che la funzione è stata chiamata.
Smontiamo il codice:
- Definiamo una funzione decoratore
mio_decoratore
che prende una funzione come argomento. - All'interno di
mio_decoratore
, definiamo una funzionewrapper
che aggiunge alcuni comportamenti prima e dopo la chiamata della funzione originale. - Utilizziamo la sintassi
@mio_decoratore
per applicare il nostro decoratore alla funzionedice_ciao
. - Quando chiamiamo
dice_ciao()
, in realtà stiamo chiamando la versione wrappata della funzione.
Non è carino? Abbiamo appena aggiunto qualche comportamento extra alla nostra funzione dice_ciao
senza modificare il suo codice!
Decoratori con Argomenti
Ma aspetta, c'è di più! Cosa facciamo se la nostra funzione prende argomenti? Nessun problema! Possiamo modificare il nostro decoratore per gestirli:
def mio_decoratore(func):
def wrapper(*args, **kwargs):
print("Prima che la funzione venga chiamata.")
risultato = func(*args, **kwargs)
print("Dopo che la funzione è stata chiamata.")
return risultato
return wrapper
@mio_decoratore
def aggiungi(a, b):
return a + b
print(aggiungi(3, 5))
Questo produrrà l'output:
Prima che la funzione venga chiamata.
Dopo che la funzione è stata chiamata.
8
Qui, *args
e **kwargs
permettono al nostro decoratore di lavorare con qualsiasi numero di argomenti posizionali e nomeati.
Decoratori Integrati
Python offre alcuni decoratori integrati incredibilmente utili. Esploriamoli!
Il Decoratore @classmethod
Il decoratore @classmethod
viene utilizzato per definire metodi che operano sulla classe stessa, piuttosto che su istanze della classe.
class Pizza:
def __init__(self, ingredienti):
self.ingredienti = ingredienti
@classmethod
def margherita(cls):
return cls(['mozzarella', 'pomodori'])
@classmethod
def prosciutto(cls):
return cls(['mozzarella', 'pomodori', 'prosciutto'])
print(Pizza.margherita().ingredienti)
print(Pizza.prosciutto().ingredienti)
Questo produrrà l'output:
['mozzarella', 'pomodori']
['mozzarella', 'pomodori', 'prosciutto']
Qui, margherita
e prosciutto
sono metodi di classe che creano e restituiscono nuove istanze di Pizza con ingredienti predefiniti.
Il Decoratore @staticmethod
I metodi statici sono metodi che non operano su istanze o classi. Sono semplicemente funzioni regolari che si trovano all'interno di una classe.
class Matematica:
@staticmethod
def aggiungi(a, b):
return a + b
print(Matematica.aggiungi(5, 10))
Questo produrrà l'output:
15
Il Decoratore @property
Il decoratore @property
ti permette di definire metodi che puoi accedere come attributi.
class Cerchio:
def __init__(self, raggio):
self._raggio = raggio
@property
def raggio(self):
return self._raggio
@property
def area(self):
return 3.14 * self._raggio ** 2
c = Cerchio(5)
print(c.raggio)
print(c.area)
Questo produrrà l'output:
5
78.5
Qui, possiamo accedere a raggio
e area
come se fossero attributi, ma in realtà sono metodi.
Il Decoratore @functools.wraps
Questo decoratore viene utilizzato per preservare i metadati della funzione originale quando si creano decoratori.
from functools import wraps
def mio_decoratore(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""Questa è la funzione wrapper"""
return func(*args, **kwargs)
return wrapper
@mio_decoratore
def mia_funzione():
"""Questa è la mia funzione"""
pass
print(mia_funzione.__name__)
print(mia_funzione.__doc__)
Questo produrrà l'output:
mia_funzione
Questa è la mia funzione
Senza @wraps
, il nome della funzione e la docstring sarebbero quelli della funzione wrapper.
Conclusione
I decoratori sono una caratteristica potente di Python che ti permette di modificare o arricchire funzioni e metodi. Sono ampiamente utilizzati nei framework e nelle librerie per aggiungere funzionalità come il logging, il controllo degli accessi e altro.
Ricorda, la chiave per padroneggiare i decoratori è la pratica. Prova a creare i tuoi decoratori e a applicarli a diverse funzioni. Presto, sarai in grado di wrappare le tue funzioni con superpoteri come un professionista!
Ecco una tabella che riassume i decoratori che abbiamo coperto:
Decoratore | Scopo |
---|---|
@classmethod |
Definisci metodi che operano sulla classe stessa |
@staticmethod |
Definisci metodi che non operano su istanze o classi |
@property |
Definisci metodi che possono essere accesi come attributi |
@functools.wraps |
Preserva i metadati della funzione originale nei decoratori |
Buon coding, e che le tue funzioni siano sempre bellissimamente decorate!
Credits: Image by storyset