lunes, 23 de diciembre de 2013

Decoradores en python

Es hora de continuar con los tutoriales de python.

Un decorador en python es esta cosa por si la han visto:

@decorador

En el código python,un decorador se usa para "modificar" una función anidandola dentro de otra,veamos un código y a continuación lo explico:

Primero que nada ya deben conocer y saber usar args y kwargs:

Enlace

Bien vamos a crear un modificador que saluda a la funcion recibida :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
def ver(fun):
   def _ver(*args,**kwargs):
      print "Bienvenido ",fun.__name__
      fun(*args,**kwargs)
      print "Adios ",fun.__name__
   return _ver

@ver
def sumar(x,y):
   print x+y
   
sumar(1,4)

Bien al ejecutar podrán ver algo como lo siguiente:

Bienvenido  sumar
5
Adios  sumar




Aquí lo que estamos haciendo es muy raro en la sintaxis común de python,porque de donde salio ese arroba no es perl o ruby para usar arrobas ,en python a eso se le llama decoradores,un decorador es una función anidada que ejecuta la función recibida y la decora adentro de otra función que retorna:

Veamos:

def ver(fun) # Esta es la función decoradora,el parámetro que recibe es la misma a decorar(la que esta abajo del arroba)

def _ver(*args,**kwargs) # Esta es la función modificada,adentro ejecutamos la función recibida y la decoramos

print "Bienvenido ",fun.__name__ # Ejecutamos esto como ejemplo de decoración(le damos la bienvenida a la funcion)

fun(*args,**kwargs) # Ejecutamos la función recibida(como si fuera la ejecución real),los parámetros los "hereda"(son los mismos)

print "Adios ",fun.__name__ # Nos despedimos de la función(podríamos decir que termina)

return _ver # Retornamos la función modificada o que modifico la función principal(la que ejecuto)

Bien,como vemos es sencillo solo que un poco raro ver esto en python,vamos a ver que contienen los args y kwargs:


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
#!/usr/bin/nev python

def ver(fun):
    def _ver(*args,**kwargs):
        print "Bienvenido ",fun.__name__
        for i in args:
            print i,"<- adentro="" del="" font="" modificador="">
        for k,v in kwargs.iteritems():
            print "Key : %s  Value : %s <- adentro="" del="" font="" modificador=""> %(k,v)
        fun(*args,**kwargs)
        print "Adios ",fun.__name__
    return _ver

@ver
def sumar(x,y,**k):
    print x+y,"<- en="" font="" funcion="" la="" real="">

sumar(1,4,uno=1)


En este caso los args y kwargs son los que le pasamos a la hora de llamarlo,por ejemplo toma de args todos los argumentos en una tupla y los kwargs todos los argumentos de clave valor,para así poder trabajar con ellos dentro del decorador por si los necesitamos,veamos un ejemplo:

Supongamos que queremos multiplicar todos los números recibidos de una funcion principal pero vamos a sumarlos también en otra función solo vamos a mostrarlos,lo cual es dos funciones una que suma y multiplica y otra que no suma solo muestra los números,podemos hacerlo 10 veces por ejemplo 7 que hagan algo con los números y 3 que solo hagan su función:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/usr/bin/nev python

def sumar(fun):
    def _sumar(*args,**kwargs):
        iterador = 0
        for i in args:
            iterador += i
        fun(*args,**kwargs)
        print "Suma de todos los numeros ",iterador
    return _sumar

@sumar
def multiplica(x,y,z,n): # Esta funcion multiplica todos los numeros
    print x*y*z*n

#@sumar # Si quitamos el gato tambien tendra el decorador sumar
def muestra(x,y,z,i): # Esta solo los muestra
    print "Numeros %d %d %d %d" %(x,y,z,i)


multiplica(1,2,3,4)

muestra(2321,321,545,565)

Bien como vemos es un uso muy raro el ejemplo pero es un ejemplo del uso de los decoradores,los ejemplos no son practica son aprendizaje así que esta bien.

Podemos usar decoradores con parámetros,por ejemplo vamos a ejecutar una función cierto numero de veces basado en el decorador:



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
#!/usr/bin/nev python

def rep(n):
    def iterador(fun):
        def _rep(*args,**kwargs):
            for i in range(0,n):
               fun(*args,**kwargs)
        return _rep
    return iterador
             
@rep(10)
def multiplica(x,y,z,n): # Esta funcion multiplica todos los numeros
    print x*y*z*n

multiplica(1,2,3,4)

Ahora lo explico:

Lo primero que hicimos fue bajar otro nivel en las funciones anidadas del decorador,el primer nivel a hora no es el que recibe la función si no el que recibe el argumento pasado al decorador:

def rep(n) # n = 10 porque @rep(10)

En la función iterador el segundo nivel de función es donde ahora recibimos la función (el decorador):

def iterador(fun) # fun = multiplica

El ultimo nivel de función es (el modificador):

def _rep(*args,**kwargs) # Modificador

En cada función en un nivel mas alto debemos retornar una función,ya que detiene la función y continua con el iterador.

return _rep termina con _rep,return iterador termina con iterador.

Como vemos los modificadores son buenos para ciertas practicas pero no son indispensables,podemos remplazarlos con funciones comunes u otras practicas,pero es bueno usarlos en ocasiones especiales.

No hay comentarios.:

Publicar un comentario

Los comentarios serán revisados antes de ser publicados.