Tutorial sobre para qué sirven y cómo utilizar en Python los decoradores además del patrón Singleton. Para este tutorial asumo que conoces python o lo has trabajado alguna vez. Todo el código usado lo tienes en el siguiente link:
Código completo en Github
Utilizar un decorador para entrada y salida de funciones
El siguiente decorador es una clase lo que hace es ejecutar la función en el __init__()
, para luego hacer una salida por medio del método __call__()
.
class my_decorator(object):
def __init__ self , f):
print("Dentro de my_decorador.__init__()")
f()
def __call__ (self):
print ("Dentro de my_decorador.__call__()")
@my_decorator
def my_function():
print("Dentro de my_function()")
print("Decorada my_function()")
my_function()
Llamar a la función dentro del decorador
Para ejecutar el código dentro de la función decoradora y jugar con él podemos pasarlo como un objeto función, dentro de los parámetros de iniciación del decorador.
class entry_exit(object):
def __init__ (self, f):
self.f = f
def __call__ ( self ):
print("Entrando en", self.f.__name__)
self.f() # Llamamos a la función dentro
print("Saliendo de", self.f,__name__)
@entry_exit
def func1():
print("Dentro de func1()")
@entry_exit
def func2 ():
print("Dentro de func2()")
func1()
func2()
En el código anterior hemos llamado a nuestras funciones a través del método call de la clase, pero realmente no necesitamos una clase para eso, podemos decorar con una función:
def entry_exit(f):
def new_f(): # Mucho más fácil
print("Entrando en" , f.__name__)
f()
print("Exited", f.__name__)
return new_f
@entry_exit
def func1():
print("inside func1()")
@entry_exit
def func2():
print("inside func2()")
func1()
func2()
Si deseas aprender más sobre temas avanzados en Python, puedes acceder a libro online Python 3 Patterns, Recipes and Idioms - Bruce Heckel & Friends. De ahí he traducido la información para este tutorial.
Pasar argumentos dentro del decorador:
class decorator_without_arguments(object):
def __init__(self, f):
"""
Si no especifivamos unos argumentos en el decorador,
la función es pasada al constructor como un objeto
"""
print("Inside __init__()")
self.f = f
def __call__(self, *args):
"""
Cuando llamamos al método __call__ disponemos de
los argumentos que hemos pasado a la función.
"""
print("Inside __call__()")
self.f(*args)
print("After self.f(*args)")
@decorator_without_arguments
def sayHello (a1, a2, a3, a4):
print('sayHello arguments:', a1, a2, a3, a4)
print ( "After decoration" )
print ("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print ("After first sayHello() call" )
sayHello("a", "different", "set of", "arguments")
print("After second sayHello() call")
La salida de este código sería:
Inside __init__()
After decoration
Preparing to call sayHello ()
Inside __call__()
sayHello arguments : say hello argument list
After self.f(*args)
After first sayHello () call
Inside __call__ ()
sayHello arguments : a different set of arguments
After self.f(*args)
After second sayHello() call
Decorador con argumentos
Si has llegado hasta aquí estárás para el siguiente código, que aunque a primera vista parezca difícil, es muy fácil.
class decorator_with_arguments(object):
# Los argumentos entran como parámetros de la clase
def __init__ (self, arg1, arg2, arg3):
# Si hay argumentos en el decorador, la función a
# ser decorada no es pasada al constructor
print ( "Inside __init__()" )
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
def __call__(self, f):
# Cuando hay argumentos en el decorador,
# la función __call__ recibe únicamente
# el objeto de la función decorada
print("Inside __call__()")
def wrapped_f(*args):
print("Inside wrapped_f()")
print("Decorator arguments:",
self.arg1, self.arg2, self.arg3)
f(*args)
print("After f(*args)")
return wrapped_f
@decorator_with_arguments("hello", "world", 42)
def sayHello(a1, a2, a3, a4):
print ('sayHello arguments:' , a1, a2, a3, a4)
print("After decoration")
print("Preparing to call sayHello()")
sayHello("say", "hello", "argument", "list")
print("after first sayHello() call")
sayHello("a", "different", "set of", "arguments")
print("after second sayHello() call")
El patrón Singleton:
Lo que hacemos con este patrón es crear una clase con una variable que se guardara en una clase interna del objeto. Si el objeto no ha sido inicializado no se ha crea la clase interna.
class SoloUno:
class __SoloUno: # El objeto interno,
def __init__(self, arg): # con su argumento
self.val = arg # se hace uno particular
def __str__(self):
return repr(self) + self.val
instance = None # Se llama sólo si no está incializado
def __init__(self, arg): # el objeto interno
if not SoloUno.instance:
SoloUno.instance = SoloUno.__SoloUno(arg)
else: # Por eso el patrón de Singleton (sólo 1)
SoloUno.instance.val = arg # Sirve para hacer objetos
def __getattr__(self, name): # de tipos diferentes, por ejemplo
return getattr(self.instance, name)
x = SoloUno('sausage')
print(x)
y = SoloUno('eggs')
print(y)
z = SoloUno('spam')
print(z) print(x)
print(y)
print('x')
print('y')
print('z')
output = '''
<__main__.__OnlyOne instance at 0076B7AC>sausage
<__main__.__OnlyOne instance at 0076B7AC>eggs
<__main__.__OnlyOne instance at 0076B7AC>spam
<__main__.__OnlyOne instance at 0076B7AC>spam
<__main__.__OnlyOne instance at 0076B7AC>spam
<__main__.SoloUno instance at 0076C54C>
<__main__.SoloUno instance at 0076DAAC>
<__main__.SoloUno instance at 0076AA3C>
'''
Uno de los propósitos más interesantes del patrón Singleton es poder crear objetos únicos con un set de atributos común a todos ellos, información que pueden intercambiar. El siguiente es 'Borg', un ejemplo de Alex Martelli:
class Borg:
_estado_compartido = {} # Atributos que a los que
def __init__(self): # accederán los objetos
self.__dict__ = self._estado_compartido
class Singleton(Borg):
def __init__(self, arg):
Borg.__init__(self)
self.val = arg
def __str__(self):
return self.val
x = Singleton('sausage')
print(x)
y = Singleton('eggs')
print(y)
z = Singleton('spam')
print(z)
print(x)
print(y)
print('x')
print('y')
print('z')
output = '''
sausage
eggs
spam
spam
spam
<__main__.Singleton instance at 0079EF2C>
<__main__.Singleton instance at 0079E10C>
<__main__.Singleton instance at 00798F9C>
''
Una versión más elegante y reducida del código anterior:
class SingleTon(object):
__instance = None
def __new__ (cls , val):
if SingleTon.__instance is None :
SingleTon.__instance = object.__new__(cls)
SingleTon.__instance.val = val
return SingleTon. __instance
Buen dia man una consulta tienes algun post donde explique como delegar el sp estuve viendo algunos tuyos de hace meses no se si tienes unos nuevos. Gracias de antemano y disculpa si por aqui no era la via para consultarte
Congratulations @mondeja! You have received a personal award!
Happy Birthday - 1 Year
Click on the badge to view your own Board of Honor on SteemitBoard.
For more information about this award, click here