Decoratori

La lezione è basata su https://realpython.com/primer-on-python-decorators/.

Un decoratore è una funzione che prende come argomento un'altra funzione e ne amplia il comportamento senza modificarla eplicitamente.

In Python le funzioni sono Oggetti di Prima Classe cioè possono essere passate come argomenti ad altre funzioni come qualunque altro oggetto (int, float, list etc.)

Possiamo definire funzioni all'interno di funzioni e una funzione può restituire funzioni:

parent restituisce una referenza (indirizzo di memoria) a una funzione (Si noti che nel return il nome della funzione è privo di parentesi tonde. Provate e restituire first_child() ), che possiamo poi invocare normalmente:

Un primo esempio di decoratore

Definiamo una funzione:

Definiamo una versione decorata di say_whee:

Possiamo anche ridefinire say_whee come la versione decorata di se stessa:

Riassumendo: un decoratore si avvolge attorno ad una funzione e ne modifica il comportamento.

Esempio 2

L'azione svolta da un decoratore può essere determinato dinamicamente, cioè quando la funzione decorata viene chiamata

Se chiamate honk fra le 22 e le 7 non succede nulla.

Esiste un modo sintetico di ridefinire una funzione come la funzione stessa inglobata in un decoratore, usando il simbolo @:

@my_decorator prima della definizione di say_whee è equivalente a definire say_whee e poi aggiugere la linea say_whee = my_decorator(say_whee).

Riutilizzare i decoratori

Se i decoratori vengono salvati in un file possono essere importati come normali funzioni e utilizzati in ambiti diversi.

Esempio:

Supponiamo che in decoratori.py ci sia il codice che segue:

def do_twice(func):
    def wrapper_do_twice():
        func()
        func()
    return wrapper_do_twice

Decorare funzioni con argomenti

Per decorare funzioni con input arbitrari è necessario utilizzare la notazione *args, **kwargs. L'input è passato al wrapper interno che a sua volta lo passa alle funzioni da decorare.

Ritornare valori da una funzione decorata

Nell'esempio seguente l'introduzione del decoratore functools.wraps serve a facilitare l'accesso alla funzione più interna

Verifichiamo che la funzione decorata ritorni effettivamente il risultato:

Decoratori nella definizione di classi

Python possiede dei decoratori built-in che vengono comunemente utilizzati nella costruzione di classi, @classmethod, @staticmethod, and @property. I decoratori @classmethod and @staticmethod vengono usati per definire metodi interni alla classe che non sono collegati alle particolari istanze della classe stessa. Il decoratore @property definisce un attributo (può essere richiamato senza le parentesi () ). In mancanza di un metodo setter l'attributo non può essere modificato dall'esterno.

Quache esempio

Decoratori, sottoclassi e inheritance

Una sottoclasse di Circle:

Qualche esempio