viernes, 25 de enero de 2008

Python - decorator con parametros

Sintetizando , podríamos decir que una función que define otra y la retorna puede actuar como decorador, y para definir un decorador con parámetros se necesitan DOS niveles de anidado. Me parece que resulta más claro - aunque sólo sea azúcar sintáctica - hacer eso mismo a través de un objeto decorador, que para transformarlo en tal sólo se necesita sobrecargar su función (), esto es, redefinir el método mágico __call__, lo que implica transformarlo en lo que en C++ se llamaría un "function object" o "functor". Está claro que la función __call__ debe recibir como parámetro a la función que se quiere decorar y devolver una función, en este caso un "wrapper", que sería el real "decorator". De esta manera el parámetro para el objeto decorador se define en su contructor, y de lo demás se encarga el operador () sobrecargado.

Sigue un ejemplo de juguete:

#!/usr/bin/env python
# --*-- coding: iso-8859-1 --*--

class ClassDecorator(object):
def __init__(self, param = 1):
self.param = param

def __call__(self, func):
def wrapper(*args, **kwargs):
print "Soy la funcion %s decorada por el No %d" % (func.__name__, self.param)
return func(*args, **kwargs)
wrapper.__name__ = func.__name__ #Esto para que no le cambie el nombre a la función decorada
#aunque si la cambiará la "firma" - los parámetros - . Para evitar eso hay que usar el módulo decorator, de Simionatto
return wrapper

def ejemplos():
#ejemplo 1: se decora definiendo al decorador en forma directa
@ClassDecorator(7)
def func1(a):
print "Soy func1, y se me asigna el parametro: %s" % a
return a

#ejemplo 2: se instancia el objecto decorador y luego se usa esa instancia
cd3 = ClassDecorator(3)
@cd3
def func2(a):
print "Soy func1, y se me asigna el parametro: %s" % a
return a

func1("uno")
print func1("dos")

func2("tres")
print func2("tres")

if __name__ == '__main__':
ejemplos()

Y para un ejemplo un poco más realista, adjunto un archivo "Yaht.py" -yet another html template- que en esencia hace lo mismo, pero cumple una función útil: el objeto Yaht se instancia tomando un documento plantilla, y modifica la plantilla buscando ciertos tokens (py-content, py-table, py-select, py-list) entre los atributos de la plantilla, y reemplazando el contenido del tag por los valores encontrados en un diccionario que debe ser devuelto por la función decorada. En esencia, es lo que hace TurboGears con Kid Template (sólo que en este caso en forma más completa y robusta que en mi ejemplo)

Espero haber contribuído algo a la confusión reinante. :=)

lunes, 23 de abril de 2007

Mi primera impresión

Crear mi primera aplicación usando tecnología Ajax ha resultado excitante y gratificante a la vez. La sensación de poder estarleyendo on line las historietas que cubrieron los años dorados de mi infancia ha sido impagable.
Pero lo más importante de todo es sentir que puedo compartir esta experiencia con todo el mundo. Losi invito a que echen un vistazo a http://silvercomics ods.org y comprueben esto por uds. mismos.
El sitio está en plena construcción ( le falta un foro, entre otras cosas ) pero ya cumple su objetivo principal, que es poderleer los comics on line.
La tecnología Cherrypy (Python) que he usado en el servidor me ha resultado una delicia.
Bueno, para no aburrir más por ésta la corto, en próximas entregas entraré en detalles técnicos de la aplicación.