Je ne peux plus vous demander (?) Python Knowledge Series -Decorator-

introduction

Classes, méthodes, itérateurs, constructeurs ... Lors de la programmation avec Python (mais sans s'y limiter), de nombreux termes et concepts techniques apparaissent. Ici, je vais vous expliquer les termes et usages que je n'entends plus, y compris la signification de Flame Learning et organiser mon esprit.

Le premier est decorator. (Il est indécis s'il faut faire la deuxième fois)

Qu'est-ce qu'un décorateur?

En un mot, c'est __ qui donne des fonctionnalités à la fonction __. Jetons un coup d'œil à un exemple de code de toute façon.

print_args_decorator.py


# -*- coding: utf-8 -*-
#Décorateur pour afficher les arguments
def print_args(func):
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print('<args is ...>')
        for arg in args:
            print(arg)
        for kwarg in kwargs:
            print('{0}:{1}'.format(kwarg, kwargs[kwarg]))
        return res
    return wrapper

Décorons la fonction avec ce décorateur. Préparez la fonction.

seimei.py


# -*- coding: utf-8 -*-
def seimei(LastName, FirstName):
    """Afficher l'argument sous forme de nom"""
    print('Nom complet:{0} {1}'.format(FirstName, LastName))

if __name__ == '__main__':
    seimei(LastName='Jackson', FirstName='Michael')
Nom complet:Michael Jackson

Nous recevons le prénom et le nom de famille et les affichons comme nom. Et si vous y ajoutiez le décorateur que vous avez créé précédemment?

seimei_deco.py


# -*- coding: utf-8 -*-
from print_args_decorator import print_args

@print_args  #Décorateur
def seimei(LastName, FirstName):
    """Afficher l'argument sous forme de nom"""
    print('Nom complet:{0} {1}'.format(FirstName, LastName))

if __name__ == '__main__':
    seimei(LastName='Jackson', FirstName='Michael')
Nom complet:Michael Jackson
<args is ...>
LastName:Jackson
FirstName:Michael

La valeur de l'argument est maintenant sortie avec la sortie de la fonction d'origine. En effet, la fonction qui renvoie le nom reçoit la fonction de sortie __arguments __. Je ne sais pas ce que c'est, mais ça semble pratique

Comment faire un décorateur

Ce qui se passe à l'intérieur du décorateur est expliqué en détail dans les articles suivants.

Sur la base de cet article et de l'exemple de code ci-dessus, je vais vous expliquer le fonctionnement de base du décorateur. (Étant donné que ce qui précède touche également à la portée, qui est un concept important en programmation, il est recommandé aux débutants de Python de le lire.)

Fonction de réception et fonction de retour

Tout d'abord, créez une pièce qui fonctionne comme décorateur. Dans l'exemple de code, il s'agit de la hiérarchie de def print_args (func): . Cette fonction spécifie une fonction comme argument. De plus, si vous regardez l'instruction return dans la même hiérarchie, vous pouvez voir qu'elle renvoie une fonction appelée wrapper. Vous recevez une fonction, la traitez (en faites un wrapper) et la renvoyez.

Définir les opérations à effectuer séparément de l'exécution de la fonction

Ensuite, créez une partie qui définit la fonction à donner. Dans l'exemple de code, il s'agit de la hiérarchie de def wrapper (* args, ** kwargs):. Dans cette fonction, la fonction reçue dans la couche supérieure est exécutée en premier. Je ne veux pas contraindre les arguments func, donc j'utilise \ * args, \ * \ * kwargs comme arguments. Puisque les décorateurs travaillent pour plusieurs fonctions et montrent leur vraie valeur, ils prennent souvent \ * args, \ * \ * kwargs comme arguments. Après avoir exécuté func, j'imprime les arguments. Notez que \ * \ * kwargs stocke ses arguments sous forme de dict, donc les arguments sont dans l'ordre de tri conforme à dict, pas dans l'ordre dans lequel ils ont été créés lorsque la fonction a été créée.

Comment utiliser le décorateur

Après avoir créé le décorateur, décorons la fonction. Le décorateur est appelé avec une marque at juste avant la définition de la fonction. Dans l'exemple de code seimei_deco.py, le décorateur print_args est appelé par @ print_args``` juste avant la fonction semei. La fonction seimei "imprime maintenant ses arguments après avoir exécuté la fonction" en plus de son comportement d'origine.

Ajoutons un décorateur à une fonction différente de l'exemple ci-dessus. Il est bon que des décorateurs puissent être ajoutés à n'importe quelle fonction, donc je pense qu'il est préférable de les créer afin qu'ils puissent être utilisés à des fins générales, telles que la spécification de \ * args, \ * \ * kwargs comme arguments.

sum_deco.py


from print_args_decorator import print_args

@print_args
def sum_print_args(*args):
    return sum(args)

if __name__ == '__main__':
    sum_num = sum_print_args(1, 3)
    print('SUM = {0}'.format(sum_num))
<args is ...>
1
3
SUM = 4

Utilisez functools.wraps

Si vous utilisez un décorateur pour générer une fonction, vous perdrez des informations telles que les chaînes de document. Cela peut être évité en utilisant functools.wraps lors de la création du décorateur. Vérifions la chaîne de document de seimei_deeco.py``` créée plus tôt.

>>> from seimei_deco import seimei
>>> print(seimei.__doc__)
None

La chaîne du document sera None. Redéfinissons le décorateur en utilisant functools.wraps et vérifions la chaîne de document de la fonction générée.

seimei_deco_use_functools.py


# -*- coding: utf-8 -*-
#Décorateur pour afficher les arguments
def print_args(func):
    import functools
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        res = func(*args, **kwargs)
        print('<args is ...>')
        for arg in args:
            print(arg)
        for kwarg in kwargs:
            print('{0}:{1}'.format(kwarg, kwargs[kwarg]))
        return res
    return wrapper

@print_args  #Décorateur
def seimei(LastName, FirstName):
    """Afficher l'argument sous forme de nom"""
    print('Nom complet:{0} {1}'.format(FirstName, LastName))

if __name__ == '__main__':
    seimei(LastName='Jackson', FirstName='Michael')
>>> from seimei_deco_use_functools import seimei
>>> print(seimei.__doc__)
Afficher l'argument sous forme de nom

La chaîne de document de la fonction d'origine s'affiche. Le point ici est que functools.wraps lui-même est utilisé comme décorateur. (J'ai fait référence à cette page) Comme mentionné précédemment, les décorateurs doivent être créés afin qu'ils puissent être utilisés à des fins générales autant que possible, donc fondamentalement functools.wraps doit être utilisé.

Où utiliser

Les décorateurs peuvent être attachés à n'importe quelle fonction. Par conséquent, il est efficace lors de l'exécution répétée de la même opération dans __ code __. Vous pouvez faire la même opération en créant une fonction au lieu d'un décorateur et en l'appelant un par un dans la définition de la fonction, mais en écrivant un peu à marquer une ligne avant la définition de la fonction, la lisibilité du code __ est améliorée. Peut être soulevé __. Ceci est très utile lorsque vous souhaitez collecter des journaux d'erreurs pour chaque méthode du module.

Aussi, quand je regarde le code du module, je vois parfois un décorateur appelé @property. Il s'agit d'une propriété de la fonction, mais je n'entrerai pas dans les détails ici. Veuillez vous reporter à cette page.

référence

Recommended Posts

Je ne peux plus vous demander (?) Python Knowledge Series -Decorator-
Séquence de Fibonacci (je ne peux plus vous demander)
J'ai essayé Python> décorateur
pyenv-vertualenv n'installe pas correctement la série python3
Je ne me souviens pas des expressions régulières Python
Scikit-learn ne peut pas être installé en Python
Je ne peux pas déboguer les scripts python dans Eclipse
J'ai repensé à la classe Python
Pourquoi ne puis-je pas installer matplotlib avec python! !!