Decoradores en python

Vamos a decorar una función bastante simple como la siguiente, la cual
suma un número variable de argumentos

def sigma(*args):
    return sum([i for i in args])

print sigma(1,2,3,4,5,6) # salida: 21

El proceso de decoración es sencillo. Tomamos una función (sigma), la ‘decoramos’ (e.g. la modificamos) con otra función y listo. La decoración de una función se puede realizar por medio de una función o por una clase.

Decorando usando funciones

Básicamente consiste en usar un wrapper sobre otra función. Este wrapper contiene la modificación que deseamos realizar sobre la función a decorar.

def logger(fn):

    def wrapper(*args):
        
        # aqui se decora la funcion
        print "some decoration..."
        return fn(*args)

    return wrapper

Esta es la estructura general para un decorador implementado como función. Note que toma como parámetro una función fn y devuelve otra función. Es decir, devuelve una versión decorada de fn, en este caso, wrapper. La funcion wrapper se encarga de realizar la decoración y llamar a la función original fn. Además, note el uso de *args, con lo cual indicamos que fn y wrapper poseen un número variable de parámetros. Hasta ahora la decoración sólo comprende en mostrar un mensaje en pantalla.

print sigma(1, 2, 3)    # salida antes de decoracion: 6

sigma = logger(sigma)   # logger devuelve una nueva funcion

print sigma(1, 2, 3)    # salida despues de decoracion:
                        # some decoration...
                        # 6

Una tarea útil usando decoradores es crear un logger de los parámetros usados. Es decir, decorar una función de manera que podamos manipular los parámetros antes de pasarlos a la funcion original, en este caso, registrarlos o mandarlos a pantalla.

def logger(fn):

    def wrapper(*args):
        
        # esta es la decoracion
        for i, arg in enumerate(args):
            print "arg %d:%d" % (i, arg)
        
        
        return fn(*args)

    return wrapper
    
sigma = logger(sigma)   # logger devuelve una nueva funcion

print sigma(1, 2, 3)    # salida despues de decoracion:
                        # arg 0:1
                        # arg 1:2
                        # arg 2:3
                        # 6

Ahora bien, para evitar esto: sigma = logger(sigma) se usa @ en la definicion
de la función a decorar:

@logger
def sigma(*args):
    return sum([i for i in args])
    
sigma(1,2,3,4)                  # arg 0:1
                                # arg 1:2
                                # arg 2:3
                                # arg 3:4

Decorando usando clases

El proceso es bastante similar. En la clase debemos definir dos funciones:

  • __init__(self, fn): Aquí agregamos la función fn a decorar en el constructor.
  • __call__(self): Es un requisito que la clase implemente esta función. Desde aquí
    podemos llamar a fn y decorarla.
class deco(object):


    def __init__(self, fn):
        
        print "before decorating..."
        self.fn = fn
        
        
    def __call__(self, *args):
        
        # esta es la decoracion
        print "decoration from class..."
        for i, arg in enumerate(args):
            print "arg %d:%d" % (i, arg)
        ########################
        
        return self.fn(*args)
    
    
    
@deco
def sigma(*args):
    return sum([i for i in args])
    
sigma(1,2,3,4)                  # before decorating...
                                # decoration from class...
                                # arg 0:1
                                # arg 1:2
                                # arg 2:3
                                # arg 3:4

Más info
aritma.com
simeon franklin
thumback.com

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s