Réintroduction aux décorateurs Python ~ Apprenons les décorateurs par type ~

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.

Personne cible

Bon à savoir

Classification des fonctions du décorateur

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?)

1. Lors du retour d'une fonction wrapper avec un décorateur sans argument

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».

2. Lorsque le décorateur avec des arguments ne renvoie pas de fonction 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'originef 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.

3. Lors du retour d'une fonction wrapper avec un décorateur avec des arguments

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.

Voyons de quel genre de décorateur il s'agit

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.

Pouvons monter les décorateurs en douceur

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

Réintroduction aux décorateurs Python ~ Apprenons les décorateurs par type ~
Entraine toi! !! Introduction au type Python (conseils de type)
Apprenez Python en dessinant (Turtle Graphics)
Python facile à apprendre en écrivant
[Introduction à l'application Udemy Python3 +] 28. Type collectif
Réponse à la sélection des débutants d'AtCoder par Python3
[Introduction à l'application Udemy Python3 +] 21. Type Taple
Fonction pour enregistrer les images par date [python3]
[Introduction à l'application Udemy Python3 +] 24. Type de dictionnaire
Livres recommandés par 3 types liés à Python
[Introduction à l'application Udemy Python3 +] 16. Type de liste
Vous voulez ajouter des indices de type aux décorateurs Python?
[python] Comment afficher les éléments de la liste côte à côte
Mis à jour vers Python 2.7.9
[Python] Comment utiliser deux types de type ()
Réintroduction à Docker
Type numérique Python
Comment effacer les caractères générés par Python
À propos de Python Decorator
Comment obtenir des éléments de type dictionnaire de Python 2.7
Type de chaîne Python2
[Python] Comment trier les instances par variables d'instance
Je souhaite vendre les produits que j'ai listés par python scraping Mercari
Python # type de chaîne
À propos des décorateurs Python
Comment gérer le type datetime dans sqlite3 de python
Exécutez Power Query en passant des arguments à Python
[Python] Suite - Convertir le texte PDF en CSV page par page
"Backport" vers python 2
Apprenez les gestes python
[Keras] Mémo personnel pour classer les images par dossier [Python]
Comment convertir le type Python # pour les super débutants de Python: str
Liste des articles liés à l'optimisation par Python vers Docker
[Réintroduction à python] Comment importer via le répertoire parent
Comment écrire un type liste / dictionnaire de Python3
[Python] Convertir le texte PDF en CSV pour chaque page (2/24 postscript)
Lisez le fichier xml en vous référant au didacticiel Python
Python - Remarques lors de la conversion du type str en type int
Comment enregistrer une table récupérée par python en csv
Python # Comment vérifier le type et le type pour les super débutants
Convertir le type d'entité Webpay en type Dict (récursivement en Python)
Apprenez le traitement / collouts asynchrones Python en comparant avec Node.js
python> datetime> De la chaîne de date (format ISO: 2015-12-09 12:40:08) au type datetime
Jugement des nombres premiers par Python
Comment installer Python
Apprenez Python avec ChemTHEATER
Mémo de visualisation par Python
Traitement de la communication par Python
Changements de Python 3.0 à Python 3.5
Changements de Python 2 à Python 3.0
Réécrire le code Python2 en Python3 (2to3)
Comment installer python
Introduction au langage Python
Introduction à OpenCV (python) - (2)
Remarque pour faire de python un démon
Introduction de Python 2.7 à CentOS 6.6
Réponse de Beamformer par python