Conozco un grupo de objetos que resuelven problemas¶
En algun lugar de Argentina, en algun momento de 2020
Ep.1 El origen de una solución
Ep.2 El problema en la serpiente
Ep.3 Cuatro porciones para llevar
Ep.4 El recambio de yerba
Hoy presentamos
Ep.1 El origen de una solución¶
Investigacion¶
{'color': str,
'isTrashed': bool,
'isPinned': bool,
'isArchived': bool,
'annotations': list,
'textContent': str,
'title': str,
'userEditedTimestampUsec': int}
# annotations
{'description': str,
'source': str,
'title': str,
'url': str}
2016: 8
2017: 69
2018: 115
2019: 98
2020: 65
Total: 355
¿Qué son los decoradores?
On the name 'Decorator'
There's been a number of complaints about
the choice of the name 'decorator' for this feature.
The major one is that the name is not consistent
with its use in the GoF book [11].
The name 'decorator' probably owes more to its
use in the compiler area -- a syntax tree
is walked and annotated.
It's quite possible that a better name may turn up.
Hoy presentamos
Ep.2 El problema en la serpiente¶
Los *decoradores*
son funciones
que reciben funciones
y devuelven funciones
Los decoradores
son aplicados una sola vez, en el momento en que se define un objeto (at definition time)
Anotar la definicion de una funcion
funcion_usual
con un decorador @decorar_con_magia
es equivalente a definir funcion_usual
e inmediatamente despues redefinirla como
funcion_usual = decorar_con_magia(funcion_usual)
def decorar_con_magia(objeto_a_decorar):
def envoltorio(argumento):
print('\N{Sparkles} Aqui hay magia \N{Sparkles}')
x = objeto_a_decorar(argumento)
print('\N{sparkles} Chin pum \N{Sparkles}')
return x
return envoltorio
def funcion_usual(argumento):
print(f'Esto es una funcion que recibio {argumento}')
return str(argumento)
decorar_con_magia(funcion_usual)(22)
✨ Aqui hay magia ✨ Esto es una funcion que recibio 22 ✨ Chin pum ✨
'22'
Decorar una funcion
primero con @extraer_lo_usual
y despues con @decorar_con_magia, en ese orden,
es equivalente a realizar
decorar_con_magia(extraer_lo_usual(otra_funcion_usual))
def extraer_lo_usual(objeto_a_decorar):
def envoltorio(arg):
print('Interceptando ...')
return f'Este llamado fue interceptado con {objeto_a_decorar.__name__}({arg})'
return envoltorio
@decorar_con_magia
@extraer_lo_usual
def otra_funcion_usual(argumento):
return f'El argumento fue {argumento}'
otra_funcion_usual(2)
✨ Aqui hay magia ✨ Interceptando ... ✨ Chin pum ✨
'Este llamado fue interceptado con otra_funcion_usual(2)'
def otra_funcion_usual(argumento):
return f'El argumento fue {argumento}'
otra_funcion_usual = decorar_con_magia(extraer_lo_usual(otra_funcion_usual))
otra_funcion_usual(2)
✨ Aqui hay magia ✨ Interceptando ... ✨ Chin pum ✨
'Este llamado fue interceptado con otra_funcion_usual(2)'
Mitos¶
Los decoradores
devuelven funciones¶
def imprimir_y_nada_mas(objeto_a_decorar):
print(objeto_a_decorar)
return objeto_a_decorar
@imprimir_y_nada_mas
def funcion_que_transforma_su_argumento(argumento):
return str(argumento) * 10
<function funcion_que_transforma_su_argumento at 0x00000175664C3600>
funcion_que_transforma_su_argumento(2)
'2222222222'
Los decoradores
son funciones¶
class GranControlador:
def __init__(self, decorando):
self._decorando = decorando
self.registro_de_llamadas = []
def __call__(self, argumento):
self.registro_de_llamadas.append(argumento)
respuesta = self._decorando(argumento)
return f'Si me lo permite, su respuesta es {respuesta}'
@GranControlador
def identidad(x):
return x
identidad('1')
'Si me lo permite, su respuesta es 1'
identidad(100)
'Si me lo permite, su respuesta es 100'
identidad.registro_de_llamadas
['1', 100]
Los decoradores
reciben funciones¶
def contar_cuantos_hay(funcion):
return funcion()
@len
@contar_cuantos_hay
def armar_lista():
return ['1',1]
armar_lista
2
Hoy presentamos
Ep.3 Cuatro porciones para llevar¶
Decoradores
para anotar¶
import unittest
suite = unittest.TestSuite()
runner = unittest.TextTestRunner()
class TesteoFallando(unittest.TestCase):
def test_que_funciona(self):
self.assertEqual(1,int(str(1)))
@unittest.skip
def test_que_no_se_porque_falla(self):
self.assertEqual(2+1-1,2.00001)
suite.addTests([TesteoFallando('test_que_funciona'),
TesteoFallando('test_que_no_se_porque_falla')
])
runner.run(suite)
.s ---------------------------------------------------------------------- Ran 1 test in 0.001s OK (skipped=1)
<unittest.runner.TextTestResult run=1 errors=0 failures=0>
Decoradores
para registrar¶
import discard
@discard.Statistics.register
class CountPosts:
def __call__(self,posts):
return len(posts)
Decoradores
para verificacion¶
import discard
@discard.Validate.clear_emails
class Content(discard.Data):
pass
Decoradores
para dispatch¶
def serializar_embellecido(x):
if isinstance(x, int):
return f'Entero({x})'
elif isinstance(x, float):
return f'Flotante({x:0.2f})'
else:
return f'OtraCosa({x})'
[serializar_embellecido(1),serializar_embellecido(0.99),serializar_embellecido(False)]
['Entero(1)', 'Flotante(0.99)', 'Entero(False)']
from functools import singledispatch
@singledispatch
def serializar_embellecido(x):
return str(x)
@serializar_embellecido.register(int)
def _(x):
return f'Entero({x})'
@serializar_embellecido.register(float)
def _(x):
return f'Flotante({x:0.2f})'
@serializar_embellecido.register(bool)
def _(x):
return f'Bool({int(x)})'
[serializar_embellecido(100),serializar_embellecido(99.9),serializar_embellecido(True)]
['Entero(100)', 'Flotante(99.90)', 'Bool(1)']
Hoy presentamos
Ep.4 El recambio de yerba¶
Es una caracteristica sintactica de Python,
syntactic sugar
Utilizarlos es una decision de disenio
- Nos permite factorizar responsabilidades
- Evitar repeticion de codigo
Cuidado¶
- Agrega complejidad en una sola linea
- Puede traer dificultades al debuguear
- No se puede obtener el objeto original una vez decorado
Una buena guia del uso de un decorador es:¶
Utilizarlo para agregar comportamiento
que es ortogonal al comportamiento original del objeto,
manteniendo el protocolo del objeto que es decorado
Gracias!¶
@sashaKile
def tweet(msg='Hola'):
twitter.post(msg)
pip install discard
Conozco un grupo de objetos que resuelven problemas
Los Decoradores:`
Ep.1 El origen de una solución Ep.2 El problema en la serpiente Ep.3 Cuatro porciones para llevar Ep.4 El recambio de yerba
En la charla voy a hablar sobre ¿Qué son los decoradores? ¿Cómo se implementan los decoradores en Python? Exponer una distinción en los distintos usos/tipos de decoradores Exponer mis opiniones sobre que tener en cuenta al utilizar decoradores
¿Qué son los decoradores?
Los decoradores como patrón de diseño,
¿Cómo se usan los decoradores en Python?
Objeto que recibe un Callable y devuelve un callable
Distinción de los distintos tipos de decoradores que se pueden implementar
Tagging, Control flow, Descriptive, Executing
Cosas importantes a tener en cuenta al utilizar decoradores
Agregar características ortogonales a nuestros objetos de manera dinámica Agrega complejidad en una sola línea de código Implementación, función, parametrizable, clase