6.1 Decoratori per metodi di classe
I decoratori possono essere utilizzati anche per i metodi di classe. È importante ricordare di passare correttamente gli argomenti self o cls.
Non abbiamo ancora affrontato nei dettagli il funzionamento delle classi, ma vorrei che sapessi che i decoratori hanno questa capacità.
def log_method_call(func):
def wrapper(self, *args, **kwargs):
print(f"Chiamata al metodo {func.__name__}")
return func(self, *args, **kwargs)
return wrapper
class MyClass:
@log_method_call
def say_hello(self):
print("Hello from MyClass!")
obj = MyClass()
obj.say_hello()
Spiegazione
Decoratore (log_method_call): Questo decoratore accetta il metodo func e restituisce una nuova funzione wrapper, che stampa un messaggio prima di chiamare il metodo.
Metodo di classe con decoratore (say_hello): Il metodo say_hello è avvolto dal decoratore log_method_call, che aggiunge un comportamento aggiuntivo quando viene chiamato.
Output:
Chiamata al metodo say_hello
Hello from MyClass!
6.2 Più decoratori
Puoi utilizzare più decoratori su una singola funzione, applicandoli uno sopra l'altro. I decoratori vengono applicati in ordine inverso rispetto alla loro dichiarazione.
def decorator1(func):
def wrapper():
print("Decoratore 1")
func()
return wrapper
def decorator2(func):
def wrapper():
print("Decoratore 2")
func()
return wrapper
@decorator1
@decorator2
def say_hello():
print("Hello!")
say_hello()
Spiegazione
Decoratori (decorator1 e decorator2): Questi decoratori aggiungono i loro messaggi prima di chiamare la funzione func.
Funzione con decoratori (say_hello): La funzione say_hello è avvolta da entrambi i decoratori. Prima viene applicato decorator2, poi decorator1.
Output:
# Decoratore 1
# Decoratore 2
Hello!
6.3 Decoratori integrati
Python fornisce diversi decoratori integrati per compiti standard, come metodi statici, metodi di classe e proprietà.
@staticmethod
Il decoratore @staticmethod è utilizzato per creare un metodo statico, che non richiede un'istanza della classe per essere chiamato.
class MyClass:
@staticmethod
def static_method():
print("Questo è un metodo statico.")
MyClass.static_method()
@classmethod
Il decoratore @classmethod è utilizzato per creare un metodo di classe, che accetta la classe (anziché l'istanza) come primo argomento.
class MyClass:
@classmethod
def class_method(cls):
print(f"Questo è un metodo di classe {cls.__name__}.")
MyClass.class_method()
@property
Il decoratore @property è utilizzato per creare getter, setter e deleter per gli attributi.
class MyClass:
def __init__(self, value):
self.hidden_value = value
@property
def value(self):
return self.hidden_value
@value.setter
def value(self, new_value):
self.hidden_value = new_value
obj = MyClass(10)
print(obj.value) # Output: 10
obj.value = 20
print(obj.value) # Output: 20
Questi sono decoratori integrati, il loro corretto funzionamento è garantito dall'interprete di Python.
6.4 Esempi di utilizzo dei decoratori
Logging
I decoratori possono essere utilizzati per loggare le chiamate a funzioni e metodi.
def log_call(func):
def wrapper(*args, **kwargs):
print(f"Chiamata alla funzione {func.__name__} con argomenti {args} e {kwargs}")
return func(*args, **kwargs)
return wrapper
@log_call
def add(x, y):
return x + y
print(add(2, 3))
Controllo dell'accesso
I decoratori possono essere utilizzati per controllare l'accesso a funzioni e metodi.
def require_authentication(func):
def wrapper(*args, **kwargs):
if not args[0].is_authenticated:
raise PermissionError("Utente non autenticato.")
return func(*args, **kwargs)
return wrapper
class User:
def __init__(self, is_authenticated):
self.is_authenticated = is_authenticated
@require_authentication
def view_profile(self):
print("Profilo utente")
user = User(is_authenticated=True)
user.view_profile() # Chiamata riuscita
user2 = User(is_authenticated=False)
user2.view_profile() # PermissionError: Utente non autenticato.
Caching
I decoratori possono essere utilizzati per memorizzare i risultati di una funzione.
def cache(func):
cached_results = {}
def wrapper(*args):
if args in cached_results:
return cached_results[args]
result = func(*args)
cached_results[args] = result
return result
return wrapper
@cache
def fib(n):
if n < 2:
return n
return fib(n - 1) + fib(n - 2)
print(fib(35))
GO TO FULL VERSION