ProgrammazioneSviluppatore Backend

Che cosa sono i decoratori per i metodi dell'istanza in Python, a cosa servono e come si applicano correttamente? Spiega il funzionamento dei decoratori classici usando funzioni e metodi come esempio.

Supera i colloqui con l'assistente IA Hintsage

Risposta.

I decoratori in Python sono storicamente emersi come un modo per rendere il codice più compatto e leggibile, incapsulando comportamenti ripetitivi attorno a funzioni e metodi. Prima dell'introduzione della sintassi @decorator, venivano applicati esplicitamente, il che complicava la comprensione del codice. Oggi, i decoratori giocano un ruolo chiave nell'organizzazione della logica, nei controlli ripetitivi, nel logging, nella memorizzazione e altro ancora.

Il problema nell'uso dei decoratori è gestire correttamente le differenze tra funzioni, metodi dell'istanza e metodi statici/classe. Spesso si verificano errori legati alla perdita di informazioni sul metodo, al binding tardivo/precoce di self e alla firma della funzione (signature).

La soluzione consiste nell'utilizzare il modulo functools.wraps per mantenere i metadati quando si scrivono decoratori universali e prestare attenzione al tipo di oggetto decorato (ad esempio, considerando correttamente che i metodi dell'istanza ricevono self come primo argomento).

Esempio di codice:

import functools def my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f"Prima della funzione: {func.__name__}") result = func(*args, **kwargs) print(f"Dopo la funzione: {func.__name__}") return result return wrapper class Esempio: @my_decorator def metodo(self, x): print(f"Metodo chiamato con {x}") ex = Esempio() ex.metodo(5)

Caratteristiche chiave:

  • Il decoratore a livello di metodo riceve la funzione, che si aspetta self come primo argomento.
  • Per preservare i metadati originali, è consigliato utilizzare functools.wraps.
  • I decoratori possono essere parametrizzati per flessibilità.

Domande trabocchetto.

Se si utilizza un decoratore scritto per una funzione su un metodo di classe, è obbligatorio utilizzare functools.wraps e cosa succederà a self?

No, il decoratore funziona, ma senza wraps si perde il nome della funzione, il supporto dell'IDE e la documentazione. Self rimarrà comunque il primo parametro, ma la perdita dei metadati complicherà il debug e la riflessione.

def bad_decorator(f): def wrapper(*args, **kwargs): print("decorato") return f(*args, **kwargs) return wrapper class Test: @bad_decorator def foo(self): pass print(Test().foo.__name__) # wrapper

È possibile applicare lo stesso decoratore sia a un metodo dell'istanza che a un metodo statico?

Sì, ma bisogna ricordare che i metodi statici non ricevono self come primo argomento. Se il decoratore è progettato per lavorare con self, si verificheranno errori con @staticmethod/@classmethod.

Come influisce il decoratore sulla firma del metodo e sul completamento automatico?

Semplicemente: senza functools.wraps, la firma e il docstring andranno persi, e l'IDE e molti strumenti di suggerimento smetteranno di funzionare correttamente.

Errori comuni e anti-pattern

  • Non utilizzare functools.wraps — perdita del nome della funzione, docstring, rende il debug più complesso.
  • Decoratore scritto per funzioni, senza considerare la presenza di self — non funziona correttamente sui metodi.
  • Riutilizzo dello stesso decoratore senza considerare il contesto (metodo statico/metodo di classe/metodo normale).

Esempio dalla vita reale

Caso negativo: Decoratori senza functools.wraps in tutti i metodi di una classe.
Vantaggi: prototipo veloce, funziona.
Svantaggi: impossibile cercare errori nello stack, l'IDE non suggerisce la firma.

Caso positivo: I decoratori usano functools.wraps, il codice è documentato.
Vantaggi: leggibilità, manutenzione, comfort dell'IDE.
Svantaggi: aggiunta minima alla sintassi e attenzione.