Chat¶

  • wpp
  • keep
  • wpp
  • tlg

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¶

keep.google.com

takeout.google.com

M¶

usa Google Keep para copiar los links y almacenarlos. Google da la posibilidad de exportar los datos a travez de takeout.google.com y pueden descargarse en formato json o html. Recientemente, empezo a armar un blog con Nikola asi que seria posible armar algo que transforme los json a un post

{'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.

PEP 318

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)

In [1]:
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
In [2]:
def funcion_usual(argumento):
    print(f'Esto es una funcion que recibio {argumento}')
    return str(argumento)
In [3]:
decorar_con_magia(funcion_usual)(22)
✨ Aqui hay magia  ✨
Esto es una funcion que recibio 22
✨ Chin pum ✨
Out[3]:
'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))

In [4]:
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
In [5]:
@decorar_con_magia
@extraer_lo_usual
def otra_funcion_usual(argumento):
    return f'El argumento fue {argumento}'
In [6]:
otra_funcion_usual(2)
✨ Aqui hay magia  ✨
Interceptando ...
✨ Chin pum ✨
Out[6]:
'Este llamado fue interceptado con otra_funcion_usual(2)'
In [7]:
def otra_funcion_usual(argumento):
    return f'El argumento fue {argumento}'
    
otra_funcion_usual = decorar_con_magia(extraer_lo_usual(otra_funcion_usual))
In [8]:
otra_funcion_usual(2)
✨ Aqui hay magia  ✨
Interceptando ...
✨ Chin pum ✨
Out[8]:
'Este llamado fue interceptado con otra_funcion_usual(2)'

Mitos¶

Los decoradores devuelven funciones¶

In [9]:
def imprimir_y_nada_mas(objeto_a_decorar):
    print(objeto_a_decorar)
    return objeto_a_decorar
In [10]:
@imprimir_y_nada_mas
def funcion_que_transforma_su_argumento(argumento):
    return str(argumento) * 10
<function funcion_que_transforma_su_argumento at 0x00000175664C3600>
In [11]:
funcion_que_transforma_su_argumento(2)
Out[11]:
'2222222222'

Los decoradores son funciones¶

In [12]:
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}'
In [13]:
@GranControlador
def identidad(x):
    return x
In [14]:
identidad('1')
Out[14]:
'Si me lo permite, su respuesta es 1'
In [15]:
identidad(100)
Out[15]:
'Si me lo permite, su respuesta es 100'
In [16]:
identidad.registro_de_llamadas
Out[16]:
['1', 100]

Los decoradores reciben funciones¶

In [17]:
def contar_cuantos_hay(funcion):
    return funcion()
In [18]:
@len
@contar_cuantos_hay
def armar_lista():
    return ['1',1]
In [19]:
armar_lista
Out[19]:
2

Hoy presentamos

Ep.3 Cuatro porciones para llevar¶

Decoradores para anotar¶

In [20]:
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)
Out[20]:
<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¶

In [21]:
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})'
In [22]:
[serializar_embellecido(1),serializar_embellecido(0.99),serializar_embellecido(False)]
Out[22]:
['Entero(1)', 'Flotante(0.99)', 'Entero(False)']
In [23]:
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)})'
In [24]:
[serializar_embellecido(100),serializar_embellecido(99.9),serializar_embellecido(True)]
Out[24]:
['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

Fuentes¶

Los Simuladores

the decorators they wont tell you about

PEP 318 - Decorators for Functions and Methods

Conozco un grupo de objetos que resuelven problemas

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

https://docs.python.org/3/library/contextlib.html?highlight=decorator

https://docs.python.org/3/library/unittest.mock-examples.html?highlight=decorator#patch-decorators

https://docs.python.org/3/library/functools.html?highlight=singledispatch#functools.singledispatch