MasciBlog

Riflessioni semiserie dal cubicolo

Decoriamo! – 3a puntata

Pubblicato da masci su 7 Maggio 2008

Dopo aver visto cosa sono i decorators in Python ed uno dei tanti modi di implementarli, approfondiamo l’argomento scrivendo un decorator un po’ più sofisticato, nella fattispecie uno che prenda un parametro:

def require(cond):
    def decorator(func):
        def wrapper(*args,**kw):
            assert eval(cond),"Requirements failed"
            return func(*args,**kw)
        return wrapper
    return decorator

@require("args[0] == 'admin'")
def login(*args):
    print "Benvenuto, %s!" % args[0]

>>> login("admin", "123456")
Benvenuto, admin!

Ovviamente invocare login("masci", "6789") solleverà un assert.

In questo modo possiamo decorare la funzione login ogni qualvolta si voglia limitare l’accesso al solo utente “admin”. Il costrutto sintattico in questo caso prevede l’utilizzo di una closure, che è il decorator vero e proprio e che prende l’oggetto funzione come parametro (l’argomento passato nella def viene invece raccolto dalla funzione più esterna). Nell’esempio sopra ho aggiunto una terza closure (wrapper) che sostituisce col solito meccanismo la funzione login.

La tecnica di cui sopra apre interessanti prospettive, ad esempio potremmo decorare una funzione in modo da imporgli una certa lista di argomenti ed il valore di ritorno, o ancora aggiungere degli attributi a runtime.

UPDATE: C’era un errore sul codice del decoratore, grazie a Loris per la segnalazione!

2 Risposte a “Decoriamo! – 3a puntata”

  1. Loris detto

    ciao, complimenti per i tre articoli sui decoratori.
    ma sull’ultimo manca la ‘func’ ?

  2. masci detto

    Sì, la funzione decorator() prendeva un parametro f ma poi nel corpo lo utilizzavo col nome func. Ovviamente non funzionava ;-) .
    Grazie per i complimenti e per la segnalazione!

Lascia un commento

XHTML: Puoi usare questi tag: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <pre> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>