logo

Décorateurs en Python

Décorateurs sont un outil très puissant et utile en Python puisqu'il permet aux programmeurs de modifier le comportement d'une fonction ou d'une classe. Les décorateurs permettent d'envelopper une autre fonction afin d'étendre le comportement de la fonction enveloppée, sans la modifier définitivement. Mais avant de plonger profondément dans les décorateurs, comprenons quelques concepts qui nous seront utiles pour apprendre les décorateurs.

Objets de première classe
En Python, les fonctions sont objets de première classe ce qui signifie que les fonctions en Python peuvent être utilisées ou passées comme arguments.
Propriétés des fonctions de première classe :

  • Une fonction est une instance du type Objet.
  • Vous pouvez stocker la fonction dans une variable.
  • Vous pouvez passer la fonction en paramètre à une autre fonction.
  • Vous pouvez renvoyer la fonction à partir d'une fonction.
  • Vous pouvez les stocker dans des structures de données telles que des tables de hachage, des listes, …

Considérez les exemples ci-dessous pour une meilleure compréhension.



Exemple 1: Traiter les fonctions comme des objets.

Python3








# Python program to illustrate functions> # can be treated as objects> def> shout(text):> >return> text.upper()> print>(shout(>'Hello'>))> yell>=> shout> print>(yell(>'Hello'>))>

>

>

Sortir:

HELLO HELLO>

Dans l'exemple ci-dessus, nous avons attribué la fonction scream à une variable. Cela n'appellera pas la fonction, mais prend l'objet fonction référencé par un cri et crée un deuxième nom pointant vers lui, criez.

Exemple 2 : Passer la fonction en argument

Python3




# Python program to illustrate functions> # can be passed as arguments to other functions> def> shout(text):> >return> text.upper()> def> whisper(text):> >return> text.lower()> def> greet(func):> ># storing the function in a variable> >greeting>=> func(>'''Hi, I am created by a function passed as an argument.'''>)> >print> (greeting)> greet(shout)> greet(whisper)>

>

>

Sortir:

HI, I AM CREATED BY A FUNCTION PASSED AS AN ARGUMENT. hi, i am created by a function passed as an argument.>

Dans l'exemple ci-dessus, la fonction greet prend une autre fonction comme paramètre (crier et chuchoter dans ce cas). La fonction passée en argument est ensuite appelée dans la fonction greet.

Exemple 3 : Renvoi de fonctions à partir d'une autre fonction.

Python3




tests de compatibilité
# Python program to illustrate functions> # Functions can return another function> def> create_adder(x):> >def> adder(y):> >return> x>+>y> >return> adder> add_15>=> create_adder(>15>)> print>(add_15(>10>))>

>

>

Sortir:

25>

Dans l'exemple ci-dessus, nous avons créé une fonction à l'intérieur d'une autre fonction, puis avons renvoyé la fonction créée à l'intérieur.
Les trois exemples ci-dessus décrivent les concepts importants nécessaires pour comprendre les décorateurs. Après les avoir parcourus, plongeons-nous maintenant en profondeur dans les décorateurs.

Décorateurs

Comme indiqué ci-dessus, les décorateurs sont utilisés pour modifier le comportement d'une fonction ou d'une classe. Dans Decorators, les fonctions sont prises comme argument dans une autre fonction, puis appelées dans la fonction wrapper.

Syntaxe pour Décorateur :

@gfg_decorator def hello_decorator(): print('Gfg') '''Above code is equivalent to - def hello_decorator(): print('Gfg') hello_decorator = gfg_decorator(hello_decorator)'''>

Dans le code ci-dessus, gfg_decorator est une fonction appelable, qui ajoutera du code au-dessus d'une autre fonction appelable, la fonction hello_decorator et renverra la fonction wrapper.

Le décorateur peut modifier le comportement :

Python3




# defining a decorator> def> hello_decorator(func):> ># inner1 is a Wrapper function in> ># which the argument is called> > ># inner function can access the outer local> ># functions like in this case 'func'> >def> inner1():> >print>(>'Hello, this is before function execution'>)> ># calling the actual function now> ># inside the wrapper function.> >func()> >print>(>'This is after function execution'>)> > >return> inner1> # defining a function, to be called inside wrapper> def> function_to_be_used():> >print>(>'This is inside the function !!'>)> # passing 'function_to_be_used' inside the> # decorator to control its behaviour> function_to_be_used>=> hello_decorator(function_to_be_used)> # calling the function> function_to_be_used()>

>

>

Sortir:

Hello, this is before function execution This is inside the function !! This is after function execution>

Voyons le comportement du code ci-dessus et comment il s'exécute étape par étape lorsque function_to_be_used est appelé.

Passons à un autre exemple où nous pouvons facilement découvrir le temps d'exécution d'une fonction en utilisant un décorateur.

Python3

convertir une chaîne en jsonobject java




# importing libraries> import> time> import> math> # decorator to calculate duration> # taken by any function.> def> calculate_time(func):> > ># added arguments inside the inner1,> ># if function takes any arguments,> ># can be added like this.> >def> inner1(>*>args,>*>*>kwargs):> ># storing time before function execution> >begin>=> time.time()> > >func(>*>args,>*>*>kwargs)> ># storing time after function execution> >end>=> time.time()> >print>(>'Total time taken in : '>, func.__name__, end>-> begin)> >return> inner1> # this can be added to any function present,> # in this case to calculate a factorial> @calculate_time> def> factorial(num):> ># sleep 2 seconds because it takes very less time> ># so that you can see the actual difference> >time.sleep(>2>)> >print>(math.factorial(num))> # calling the function.> factorial(>10>)>

>

>

Sortir:

3628800 Total time taken in : factorial 2.0061802864074707>

Que se passe-t-il si une fonction renvoie quelque chose ou si un argument est passé à la fonction ?

Dans tous les exemples ci-dessus, les fonctions n'ont rien renvoyé, donc il n'y a pas eu de problème, mais on peut avoir besoin de la valeur renvoyée.

Python3




def> hello_decorator(func):> >def> inner1(>*>args,>*>*>kwargs):> > >print>(>'before Execution'>)> > ># getting the returned value> >returned_value>=> func(>*>args,>*>*>kwargs)> >print>(>'after Execution'>)> > ># returning the value to the original frame> >return> returned_value> > >return> inner1> # adding decorator to the function> @hello_decorator> def> sum_two_numbers(a, b):> >print>(>'Inside the function'>)> >return> a>+> b> a, b>=> 1>,>2> # getting the value through return of the function> print>(>'Sum ='>, sum_two_numbers(a, b))>

>

>

Sortir:

before Execution Inside the function after Execution Sum = 3>

Dans l'exemple ci-dessus, vous remarquerez peut-être une nette différence dans les paramètres de la fonction interne. La fonction interne prend l'argument sous la forme *args et **kwargs, ce qui signifie qu'un tuple d'arguments de position ou un dictionnaire d'arguments de mots-clés peut être transmis de n'importe quelle longueur. Cela en fait un décorateur général capable de décorer une fonction ayant un nombre illimité d'arguments.

Enchaînement des décorateurs

En termes plus simples, enchaîner des décorateurs signifie décorer une fonction avec plusieurs décorateurs.

Exemple:

Python3




# code for testing decorator chaining> def> decor1(func):> >def> inner():> >x>=> func()> >return> x>*> x> >return> inner> def> decor(func):> >def> inner():> >x>=> func()> >return> 2> *> x> >return> inner> @decor1> @decor> def> num():> >return> 10> @decor> @decor1> def> num2():> >return> 10> > print>(num())> print>(num2())>

>

>

Sortir:

400 200>

L'exemple ci-dessus est similaire à l'appel de la fonction comme –

decor1(decor(num)) decor(decor1(num2))>