ProgrammazioneSviluppatore Backend

Che cosa sono i decoratori di funzioni di ordine superiore in Python, come permettono di implementare il pattern 'wrapping' e cosa si deve considerare quando si lavora con i metadati/documentazione della funzione?

Supera i colloqui con l'assistente IA Hintsage

Risposta.

In Python, un decoratore di funzione di ordine superiore è una funzione che accetta un'altra funzione (o una classe) e restituisce una nuova funzione (o una classe modificata). I decoratori vengono spesso utilizzati per implementare il pattern "wrapping" (avvolgimento), che consente di aggiungere logica aggiuntiva (ad esempio, registrazione, caching, controllo dei diritti, ecc.) a funzioni esistenti senza modificare il loro codice sorgente.

Per mantenere il nome, la documentazione e altri metadati della funzione originale, si consiglia di utilizzare la funzione functools.wraps:

import functools def log_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): print(f'Chiamando {func.__name__}') return func(*args, **kwargs) return wrapper @log_decorator def add(a, b): """Aggiungi due numeri""" return a + b print(add(2, 3)) # Output: Chiamando add 5 print(add.__name__) # Output: add print(add.__doc__) # Output: Aggiungi due numeri

Punto chiave: senza functools.wraps, la funzione avvolta perderà nome, documentazione e altri metadati dell'originale, il che influisce negativamente sul debug e sulla generazione automatica della documentazione.

Domanda ingannevole.

Cosa succede se decoriamo una funzione senza usare functools.wraps, quali saranno gli attributi name e doc della funzione?

Risposta: Saranno ereditati dalla funzione interna avvolgente (di solito 'wrapper'), e si perderanno i metadati originali.

def simple_decorator(func): def wrapper(*args, **kwargs): return func(*args, **kwargs) return wrapper @simple_decorator def f(): """Questa è la docstring""" pass print(f.__name__) # Output: 'wrapper' (NON 'f') print(f.__doc__) # Output: None (non 'Questa è la docstring')

Esempi di errori reali a causa della mancanza di conoscenza delle sfumature dell'argomento.


Storia

In un progetto è stato implementato un complesso sistema di decoratori per la registrazione degli endpoint API, ma non è stato usato functools.wraps. Di conseguenza, la generazione automatica della documentazione (Swagger/OpenAPI) e gli strumenti di introspezione mostravano i nomi di tutti gli endpoint come 'wrapper', e la documentazione era scomparsa. Questo ha reso molto difficile la manutenzione, i test e l'assistenza.


Storia

Durante la scrittura dei test unitari con pytest si è verificato un errore di auto-scoperta dei test: le funzioni di test decorate con i propri decoratori senza wraps non venivano riconosciute, poiché il loro name era errato. La ragione è che pytest cerca le funzioni per nome.


Storia

Durante il tracciamento dello stack delle eccezioni (traceback), lo stack-trace puntava sempre a "wrapper", ed era impossibile capire quale funzione avesse causato l'errore, poiché i metadati originali erano andati persi a causa della mancanza di functools.wraps nei decoratori personalizzati.