English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Le décorateur accepte une fonction, ajoute des fonctionnalités et la retourne. Dans cet article, vous apprendrez à créer des décorateurs et pourquoi il est utile de les utiliser.
Python a une fonctionnalité intéressante appeléeDécorateurs, peut ajouter des fonctionnalités au code existant.
Ce qui est également appeléMeta-programmation,Parce qu'une partie du programme tente de modifier une autre partie du programme lors de la compilation.
Pour comprendre les décorateurs, nous devons d'abord comprendre certaines connaissances de base en Python.
Nous devons accepter le fait que tout contenu en Python estObjets. Les noms que nous définissons ne sont que des identifiants liés à ces objets.FonctionsCe n'est pas non plus le cas, elles sont également des objets (avec des attributs). Vous pouvez lier divers noms à la même fonctionnel object.
C'est un exemple.
def first(msg): print(msg) first("Hello") second = first second("Hello")
Lorsque vous exécutez le code, ces deux fonctions first et second donnent le même résultat. Ici, les noms first et second font référence au même objet fonctionnel.
Maintenant, n'est-ce pas un peu plus complexe, transmettre une fonction à une autre fonction en tant que paramètre ?
Si vous avez utilisé des fonctions telles que map, filter et reduce en Python, vous savez déjà cela.
Ces fonctions qui prennent d'autres fonctions en paramètres sont également appeléesFonctions de haute ordre. Voici un exemple de ce genre de fonction.
def inc(x): return x + 1 def dec(x): return x - 1 def operate(func, x): result = func(x) return result
Nous appelons la fonction comme suit.
>>> operate(inc,3) 4 >>> operate(dec,3) 2
En outre, une fonction peut retourner une autre fonction.
def is_called(): def is_returned(): print("Hello") return is_returned new = is_called() #Sortie "Hello" new()
Ici, is_returned() est une fonction imbriquée qui est définie et retournée chaque fois que nous appelons is_drawn().
Enfin, nous devons comprendreLes closures en Python.
Les fonctions et les méthodes sont appeléesAppelable,Parce qu'ils peuvent être appelés.
En réalité, tout objet qui implémente la méthode spéciale __call__() est appelé appelable. Par conséquent, dans le sens le plus basique, les décorateurs sont appelables et peuvent retourner des objets appelables.
En règle générale, les décorateurs acceptent une fonction, ajoutent des fonctionnalités et la retournent.
def make_pretty(func): def inner(): print("Je suis décoré") func() return inner def ordinary(): print("Je suis une fonction ordinaire")
Lorsque vous exécutez le code suivant dans le shell,
>>> ordinary() Je suis une fonction ordinaire >>> # Nous allons décorer cette fonction ordinaire >>> pretty = make_pretty(ordinary) >>> pretty() Je suis décoré Je suis une fonction ordinaire
Dans l'exemple montré ci-dessus, make_pretty() est un décorateur dans l'étape d'affectation.
pretty = make_pretty(ordinary)
La fonction ordinary() est décorée, et la fonction retournée s'appelle pretty.
Nous pouvons voir que le décorateur ajoute de nouvelles fonctionnalités à la fonction originale. C'est comme emballer un cadeau. Le décorateur joue le rôle d'emballage. La nature de l'article décoré (le cadeau à l'intérieur) ne change pas. Mais maintenant, il a l'air joli (depuis qu'il a été décoré).
En règle générale, nous décorons une fonction et la réaffectons,
ordinary = make_pretty(ordinary).
C'est une construction courante, donc Python a simplifié cette syntaxe.
Nous pouvons utiliser le symbole @ avec le nom du décorateur et le placer au-dessus de la définition de la fonction à décorer. Par exemple,
@make_pretty def ordinary(): print("Je suis une fonction ordinaire")
is equivalent to
def ordinary(): print("Je suis une fonction ordinaire") ordinary = make_pretty(ordinary)
C'est juste un sucre syntaxique pour l'implémentation des décorateurs.
Le décorateur ci-dessus est simple et ne s'applique qu'aux fonctions sans paramètres. Que faire si notre fonction a des paramètres comme ceux-ci ?
def divide(a, b): return a/b
Cette fonction a deux paramètres,aandbNous savons que si nous allonsbSi on passe 0, cela produit une erreur.
>>> divide(2,5) 0.4 >>> divide(2,0) Traceback (appel le plus récent en dernier) : ... ZeroDivisionError : division par zéro
Nous allons maintenant créer un décorateur pour vérifier si cela peut entraîner une erreur.
def smart_divide(func): def inner(a,b): print("Je vais faire une division", a, "et", b) if b == 0: print("Ah ! Je ne peux pas diviser") return return func(a,b) return inner @smart_divide def divide(a,b): return a/b
If an error occurs, this new implementation will return None.
>>> divide(2,5) I want to do division 2 and 5 0.4 >>> divide(2,0) I want to do division 2 and 0 Oh no! Can't divide
In this way, we can decorate functions with parameters.
Perceptive observers will notice that the parameters of the nested function inside the inner() decorator are the same as those of the function it decorates. Considering this, now we can make the generic decorator usable with any number of arguments.
In Python, this magic is done through the completion of the function(*args, **kwargs).So, args are positional argumentsTupleinstead of positional arguments,Dictionary.An example of such a decorator is.
def works_for_all(func): def inner(*args, **kwargs): I can decorate any function return func(*args, **kwargs) return inner
Multiple decorators can be linked in Python.
This means that a function can be decorated multiple times (or the same) with different decorators. We just need to place the decorators above the required function.
def star(func): def inner(*args, **kwargs): print("*" * 30) func(*args, **kwargs) print("*" * 30) return inner def percent(func): def inner(*args, **kwargs): print("%") * 30) func(*args, **kwargs) print("%") * 30) return inner @star @percent def printer(msg): print(msg) printer("Hello")
this will give the output.
****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Hello %%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ******************************
the above syntax,
@star @percent def printer(msg): print(msg)
is equivalent to
def printer(msg): print(msg) printer = star(percent(printer))
The order of the link decorators is important. If we do it in the opposite order,
@percent @star def printer(msg): print(msg)
The execution will occur
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% ****************************** Hello ****************************** %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%