Skip to content

Instantly share code, notes, and snippets.

@PiDroid-B
Last active May 28, 2021 12:03
Show Gist options
  • Save PiDroid-B/1e2002e18b33b80a31767cde6d321bbf to your computer and use it in GitHub Desktop.
Save PiDroid-B/1e2002e18b33b80a31767cde6d321bbf to your computer and use it in GitHub Desktop.
Python - exemple décorateurs
# qui est quoi, identification des différents éléments
def deco1():
print("IN deco1")
def fonc1():
print("IN fonc1")
return "return fonc1"
print("OUT deco1")
return fonc1
>>> mon_test = deco1()
IN deco1
OUT deco1
>>> mon_test
<function deco1.<locals>.fonc1 at 0x7f8e6e5694c0>
>>> mon_test.__name__
'fonc1'
>>> print(f"mon_test renvoie '{mon_test()}'")
IN fonc1
mon_test renvoie 'return fonc1'
# un décorateur qui décore une fonction
def deco2(func):
print(f"IN deco2, ARG func = {func.__name__}")
def fonc2(*args, **kwargs):
print(f"IN fonc2 and RUN func {func.__name__} with {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"OUT fonc2 and return result of {func.__name__} exec")
return result
print("OUT deco2")
return fonc2
>>> @deco2
... def toto():
... print("toto")
...
IN deco2, ARG func = toto
OUT deco2
# OU
>>> def toto():
... print("toto")
...
>>> toto = deco2(toto)
IN deco2, ARG func = toto
OUT deco2
>>> toto()
IN fonc2 and RUN func toto
toto
OUT fonc2 and return result of toto exec
# De même pour une fonction avec arguement
>>> @deco2
... def titi(a,b):
... print(f"{a} et {b}")
...
IN deco2, ARG func = titi
OUT deco2
>>> titi("c'est parti", b="mon kiki")
IN fonc2 and RUN func titi with ("c'est parti",), {'b': 'mon kiki'}
c'est parti et mon kiki
OUT fonc2 and return result of titi exec
>>> @deco2
... @deco2
... def pouet(a):
... print(a)
...
IN deco2, ARG func = pouet
OUT deco2
IN deco2, ARG func = fonc2
OUT deco2
>>> pouet('dsdf')
IN fonc2 and RUN func fonc2 with ('dsdf',), {}
IN fonc2 and RUN func pouet with ('dsdf',), {}
dsdf
OUT fonc2 and return result of pouet exec
OUT fonc2 and return result of fonc2 exec
# un décorateur qui inclus un autre décorateur
def deco3a(func):
print(f"IN deco3a, ARG func = {func.__name__}")
def fonc3a(*args, **kwargs):
print(f"IN fonc3a and RUN func {func.__name__} with {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"OUT fonc3a and return result of {func.__name__} exec")
return result
print("OUT deco3a")
return fonc3a
def deco3b(func):
print(f"IN deco3b, ARG func = {func.__name__}")
@deco3a
def fonc3b(*args, **kwargs):
print(f"IN fonc3b and RUN func {func.__name__} with {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"OUT fonc3b and return result of {func.__name__} exec")
return result
print("OUT deco3b")
return fonc3b
>>> @deco3b
... def toto():
... print("toto")
...
IN deco3b, ARG func = toto
IN deco3a, ARG func = fonc3b
OUT deco3a
OUT deco3b
>>> toto()
IN fonc3a and RUN func fonc3b with (), {}
IN fonc3b and RUN func toto with (), {}
toto
OUT fonc3b and return result of toto exec
OUT fonc3a and return result of fonc3b exec
>>> @deco3b
... def titi(a,b):
... print(f"{a} {b}")
...
IN deco3b, ARG func = titi
IN deco3a, ARG func = fonc3b
OUT deco3a
OUT deco3b
>>> titi("c'est parti", b="mon kiki")
IN fonc3a and RUN func fonc3b with ("c'est parti",), {'b': 'mon kiki'}
IN fonc3b and RUN func titi with ("c'est parti",), {'b': 'mon kiki'}
c'est parti mon kiki
OUT fonc3b and return result of titi exec
OUT fonc3a and return result of fonc3b exec
# décorateur avec paramètres
def deco4param(param_in, param_out):
print(f"IN deco4param : {param_in}")
def deco4(func):
print(f"IN deco4, ARG func = {func.__name__}")
def fonc4(*args, **kwargs):
print(f"IN fonc4 and RUN func {func.__name__} with {args}, {kwargs}")
print(f"params : {param_in}, {param_out}")
result = func(*args, **kwargs)
print(f"OUT fonc4 and return result of {func.__name__} exec")
return result
print("OUT deco4")
return fonc4
print(f"OUT deco4param : {param_out}")
return deco4
>>> @deco4param("input","output")
... def toto(pouet):
... print(pouet)
...
IN deco4param : input
OUT deco4param : output
IN deco4, ARG func = toto
OUT deco4
>>>
>>> toto("hoho !")
IN fonc4 and RUN func toto with ('hoho !',), {}
params : input, output
hoho !
OUT fonc4 and return result of toto exec
# un décorateur avec paramètre qui inclus un autre décorateur avec paramètre
def deco5a_param(param_in, param_out):
print(f"IN deco5a_param : {param_in}")
def deco5a(func):
print(f"IN deco5a, ARG func = {func.__name__}")
def fonc5a(*args, **kwargs):
print(f"IN fonc5a and RUN func {func.__name__} with {args}, {kwargs}")
print(f"params : {param_in}, {param_out}")
result = func(*args, **kwargs)
print(f"OUT fonc5a and return result of {func.__name__} exec")
return result
print("OUT deco5a")
return fonc5a
print(f"OUT deco5a_param : {param_out}")
return deco5a
def deco5b_param(param_in, param_out):
print(f"IN deco5b_param : {param_in}")
def deco5b(func):
print(f"IN deco5b, ARG func = {func.__name__}")
def fonc5b(*args, **kwargs):
print(f"IN fonc5b and RUN func {func.__name__} with {args}, {kwargs}")
print(f"params : {param_in}, {param_out}")
result = func(*args, **kwargs)
print(f"OUT fonc5b and return result of {func.__name__} exec")
return result
print("OUT deco5b")
return (deco5a_param(param_in, param_out))(fonc5b)
print(f"OUT deco5b_param : {param_out}")
return deco5b
>>> @deco5b_param("in","ou")
... def toto(a):
... print(a)
...
IN deco5b_param : in
OUT deco5b_param : ou
IN deco5b, ARG func = toto
OUT deco5b
IN deco5a_param : in
OUT deco5a_param : ou
IN deco5a, ARG func = fonc5b
OUT deco5a
>>> toto("haha")
IN fonc5a and RUN func fonc5b with ('haha',), {}
params : in, ou
IN fonc5b and RUN func toto with ('haha',), {}
params : in, ou
haha
OUT fonc5b and return result of toto exec
OUT fonc5a and return result of fonc5b exec
import functools
# command = décorateur que l'on souhaite encapsuler/mettre en cache
def command(parameter=None):
def decorator(func):
print('Evaluate decorator')
def wrapped(*args, **kwargs):
print(f'Func called with parameter {parameter!r}')
return func(*args, **kwargs)
return wrapped
return decorator
# get_parameter sera mise en cache à la première exécution
# le cache sera utilisé pour les exécutions suivantes au lieu de get_parameter()
@functools.cache
def get_parameter():
# Hard computation to get parameter
print('Make hard computation')
return (400 * 1291 * 13 - 1).to_bytes(3, 'big').decode()
# idem avec get_decorator (autnat de cache que d'appel de get_decorator un paramètre différent)
@functools.cache
def get_decorator(func):
# parameter de command est récupéré depuis get_parameter (ou depuis le cache)
decorator = command(parameter=get_parameter())
return decorator(func)
def my_command():
def decorator(func):
def wrapped(*args, **kwargs):
# on récupère get_decorator (ou son équivalent en cache)
new_func = get_decorator(func)
return new_func(*args, **kwargs)
return wrapped
return decorator
# le paramètre (get_parameter) à transmettre à 'command' est mise en cache
# le décorateur get_decorator(func) est mise en cache pour chaue func et appelera command avec get_parameter comme paramètre
@my_command()
def pouet(a, b):
return a + b
@my_command()
def toto(a, b):
return a - b
print('-' * 80)
print(pouet(1, 2))
print(toto(1, 2))
print(pouet(3, 4))
print(toto(3, 4))
deco1 : identifications des éléments
deco2 : décorateur simple
deco3 : décorateurs qui inclus un autre décorateur
deco4 : décorateur avec paramètres
deco5 : décorateur avec paramètre qui inclus un autre décorateur avec paramètre
deco6 : décorateur avec mise en cache et incluant un autre décorateur
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment