Voici un résumé des décorateurs, qui sont des notations utilisant le atmark Python (@). Cela peut sembler difficile à décorer, mais je pensais que c'était un raccourci pour comprendre le type (motif) du décorateur, donc cette fois je vais l'expliquer en donnant un exemple simple de mise en œuvre du décorateur pour chaque type. pense.
* args
, ** kwargs
Il semble que la fonction de décorateur puisse être classée par les deux facteurs suivants.
Par conséquent, un total de quatre modèles peut être considéré à partir des combinaisons, mais cette fois, nous en introduirons trois à l'exception des "décorateurs qui ne prennent pas d'arguments et renvoient des fonctions d'encapsulation". La raison pour en exclure un est trop simple pour avoir un sens.
Comme définition des termes, nous appellerons la fonction avec le décorateur (la fonction définie sous @ decorator
) ** la fonction d'origine ** (y a-t-il un bon nom?)
def args_logger(f):
def wrapper(*args, **kwargs):
f(*args, **kwargs)
print('args: {}, kwargs: {}'.format(args, kwargs))
return wrapper
@args_logger
def print_message(msg):
print(msg)
#Équivalent à
'''
def print_message(msg):
print(msg)
print_message = args_logger(print_message)
'''
print_message('hello')
Résultat d'exécution
hello
args: ('hello',), kwargs: {}
Tout d'abord, celui qui est le plus facile à comprendre. La fonction «args_logger» renvoie une fonction wrapper qui affiche () les informations d'argument de la fonction d'origine.
En d'autres termes, la fonction avec @ args_logger
crachera des informations d'argument à chaque fois qu'elle est exécutée.
Comme dans cet exemple, il est habituel de nommer la fonction wrapper renvoyée «wrapper».
funcs = []
def appender(*args, **kwargs):
def decorator(f):
#Selon le contenu des args et des kwargs, le contenu du traitement peut être modifié ou non.
print(args)
if kwargs.get('option1'):
print('option1 is True')
#Ajouter une fonction originale aux funcs
funcs.append(f)
return decorator
@appender('arg1', option1=True)
def hoge():
print('hoge')
@appender('arg2', option2=False)
def fuga():
print('fuga')
#Équivalent à
'''
def hoge():
print('hoge')
appender('arg1', option1=True)(hoge)
def fuga():
print('fuga')
appender('arg2', option2=False)(fuga)
'''
for f in funcs:
f()
Résultat d'exécution
('arg1',)
option1 is True
('arg2',)
hoge
fuga
ʻAppenderLe décorateur ajoute la fonction d'origine à la liste des fonctions. Vous pouvez modifier le contenu du traitement en fonction de l'argument passé à la fonction décorateur (je ne pouvais pas penser à un bon exemple cette fois, donc je l'ai juste imprimé de manière appropriée). Notez que si vous conservez l'argument dans le décorateur, vous ne pouvez pas gérer la fonction d'origine
f directement dans la fonction décorateur. Au lieu de cela, définissez une «fonction qui gère la fonction d'origine». Ce nom de fonction est habituellement nommé «décorateur» (probablement). La fonction ʻapp / Flask.route
de Flask s'applique comme décorateur pour ce modèle.
https://github.com/pallets/flask/blob/3a0ea726bd45280de3eb3042784613a676f68200/flask/app.py#L1222
Il semble que ce modèle soit utilisé simplement pour définir une fonction de rappel comme flask.
def args_joiner(*dargs, **dkwargs):
def decorator(f):
def wrapper(*args, **kwargs):
newargs = dargs + args #Rejoindre la liste
newkwargs = {**kwargs, **dkwargs} #Combiner des dictionnaires(python3.Fonctionne avec 5 ou plus)
f(*newargs, **newkwargs)
return wrapper
return decorator
@args_joiner('darg', dkwarg=True)
def print_args(*args, **kwargs):
print('args: {}, kwargs: {}'.format(args, kwargs))
#Équivalent à
'''
def print_args(*args, **kwargs):
print('args: {}, kwargs: {}'.format(args, kwargs))
print_args = args_joiner('darg', dkwarg=True)(print_args)
'''
print_args('arg', kwarg=False)
Résultat d'exécution
args: ('darg', 'arg'), kwargs: {'kwarg': False, 'dkwarg': True}
Cela s'est compliqué avec le sentiment d'une combinaison des premier et deuxième exemples. ʻArgs_joiner` Le décorateur renvoie une fonction qui prend un argument qui concatène l'argument de la fonction d'origine et l'argument du décorateur (le processus de concaténation des arguments n'a pas de sens profond, juste un exemple). Notez que l'imbrication est devenue plus profonde une fois lorsque "le retour d'une fonction est renvoyé". Si vous faites de votre mieux pour suivre le processus, vous saurez ce que vous faites.
Résumé à travers trois exemples. Pour comprendre ce que fait le décorateur, il est facile de voir de quel genre de décorateur il s'agit.
Par exemple, comme le premier exemple
def hoge_deco(func):
def wrapper(...):
...
return wrapper
S'il est écrit comme ceci, il serait bien de savoir instantanément que le décorateur hoge_deco
n'est ** aucun argument ** et ** une fonction wrapper est renvoyée **. Le matériel de jugement est que «func» est considéré comme l'argument de «hoge_deco», et que la fonction «wrapper» est définie et elle est renvoyée à la fin.
Comme le deuxième exemple
def fuga_deco(*args, **kwargs):
def decorator(f):
# args, kwargs,Faites quelque chose avec f(Ajouter f à une liste, etc.)
...
return decorator
S'il est écrit de cette façon, considérez le décorateur fuga_deco
comme ** un argument ** décorateur qui ** ne renvoie pas de fonction wrapper **. Le matériel de jugement est que quelque chose d'autre qu'une fonction est pris dans l'argument de fuga_deco
, et une fonction nommée decorator
qui prend la fonction f
comme argument au lieu du nom wrapper
est définie. Est de retour. Notez que le décorateur de ce modèle ne renvoie pas de fonction wrapper, donc la fonction d'origine elle-même ne change pas du tout.
Comme dans le troisième exemple
def piyo_deco(*dargs, **dkwargs):
def decorator(f):
...
def wrapper(*args, **kwargs):
...
return wrapper
return decorator
Si c'est le cas, le décorateur piyo_deco
est ** un argument ** décorateur qui renvoie une ** fonction wrapper **. Est-il acceptable de prendre une décision?
Quel genre de décorateur y a-t-il dans cet exemple? Je ne peux pas y penser un instant, mais je pense qu'il y en a pas mal.
Si vous pouvez comprendre le code du décorateur, il sera plus facile de fabriquer vous-même le décorateur. Je pense que je peux écrire presque avec n'importe lequel des trois modèles cette fois, alors réfléchissez d'abord au modèle dont vous avez besoin, puis écrivez mécaniquement * arg, ** args
, def wrapper
ou def decorator
. Si vous le pouvez, vous pouvez être appelé un maître décorateur.
Je n'ai jamais fait de décorateur moi-même, mais écrire cet article a été une bonne critique. Je veux décorer bang bang à partir de maintenant!
Recommended Posts