jueves, 28 de julio de 2011

Decoradores en python (I)

Llevo poco tiempo programando en python, y una de las cosas que más me ha sorpendido es el tema de los decoradores. Estan basado en el patron decorador, y existen tambien en otros lenguajes, pero en python esta muy bien integrado. Los decoradores nos sirven para añadir nuevas funcionalidades a codigo ya existente, o reutilizar código de forma más eficiente, y sobre todo tambien, para que quede el codigo más legible. En está pagina podemos ver que lo utiliza para evitar la repetición de código, y para que quede más clara. A continuación voy a poner un ejemplo muy simple de decorador, que simplemente nos dice cuando se ejecuta la parte perteneciente al decorador con un print: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 # Nuestro decorador def saluda_antes(funcion): print "Codigo antes de decorar la funcion" def nueva_funcion(*args, **kwargs): print "Ejecuto la funcion decorada" return funcion(*args, **kwargs) print "Codigo despues de decorar la funcion" return nueva_funcion # Nuestra funcion def sumar(a, b): print "Ejecutando suma" return a+b # Main if __name__ == '__main__': sol = sumar(2, 3) print "Solucion {0}\n".format(sol) print "Decoramos la funcion_______________" sumar = saluda_antes(sumar) print "Funcion ya decorada________________\n" sol = sumar(2, 3) print "Solucion {0}".format(sol) Que nos genera la siguiente salida: Ejecutando suma Solucion 5 Decoramos la funcion_______________ Codigo antes de decorar la funcion Codigo despues de decorar la funcion Funcion ya decorada________________ Ejecuto la funcion decorada Ejecutando suma Solucion 5 En el primer bloque vemos la funcion sumar a secas. En el segundo la salida que nos muestra es la que obtenemos mientras se aplica el decorador. Y por ultimo tenemos el resultado de lanzar la funcion con el decorador aplicado. Otra manera de lanzar el decorador es poniendo la @nombre_decorador encima de la función. ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 # Nuestro decorador def saluda_antes(funcion): print "Codigo antes de decorar la funcion" def nueva_funcion(*args, **kwargs): print "Ejecuto la funcion decorada" return funcion(*args, **kwargs) print "Codigo despues de decorar la funcion" return nueva_funcion # Nuestra funcion @saluda_antes def sumar(a, b): print "Ejecutando suma" return a+b # Main if __name__ == '__main__': sol = sumar(2, 3) print "Solucion {0}".format(sol) Que genera una salida ligeramente diferente: Codigo antes de decorar la funcion Codigo despues de decorar la funcion Ejecuto la funcion decorada Ejecutando suma Solucion 5 Podemos ver que lo primero que se ejecuta es el código que hay al decorar la funcion, seguido por el código del decorador, y por último el de la funcion. Creo que queda claro, pero solo quiero aclarar que el codigo que se ejecuta al decorar la funcion (al principio), sólo se ejecuta una única vez. Si hicieramos 4 llamadas seguidas, tendriamos algo tal que así: Codigo antes de decorar la funcion Codigo despues de decorar la funcion Ejecuto la funcion decorada Ejecutando suma Solucion 5 Ejecuto la funcion decorada Ejecutando suma Solucion 5 Ejecuto la funcion decorada Ejecutando suma Solucion 5 Ejecuto la funcion decorada Ejecutando suma Solucion 5 Y hasta aquí lo que se daba. Volvere con más operadores cuando aprenda un poco más sobre ellos (paso de parametros, autocreacion de decoradores, etc).

1 comentario:

  1. Hola!.
    Eso de que están basados en el patrón decorador... no lo veo tan claro, en otros artículos dicen lo contrario.. te paso uno de ellos:
    http://www.3engine.net/wp/2015/02/decoradores-python/

    ResponderEliminar