From 600b2b5f8a07ed24d402580156861a744e9f0236 Mon Sep 17 00:00:00 2001 From: Dimitri Merejkowsky Date: Sat, 21 Mar 2020 11:10:33 +0100 Subject: [PATCH] =?UTF-8?q?Fin=20du=20cours=20sur=20les=20d=C3=A9corateurs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../02-portée-des-variables.rst | 2 + .../19-functions-02/01-introduction.rst | 55 ++++++++++++- .../19-functions-02/02-décorateurs.rst | 80 +++++++++++++++---- cours/source/19-functions-02/index.rst | 6 +- 4 files changed, 119 insertions(+), 24 deletions(-) diff --git a/cours/source/06-fonctions-01/02-portée-des-variables.rst b/cours/source/06-fonctions-01/02-portée-des-variables.rst index 4dc09a0..b037894 100644 --- a/cours/source/06-fonctions-01/02-portée-des-variables.rst +++ b/cours/source/06-fonctions-01/02-portée-des-variables.rst @@ -1,3 +1,5 @@ +.. _portées-des-variables: + Portée des variables ==================== diff --git a/cours/source/19-functions-02/01-introduction.rst b/cours/source/19-functions-02/01-introduction.rst index 987061f..0d8cfcc 100644 --- a/cours/source/19-functions-02/01-introduction.rst +++ b/cours/source/19-functions-02/01-introduction.rst @@ -57,7 +57,22 @@ il y a en réalité deux étapes: 1. Python stocke le corps de la fonction quelque part 2. Il crée une variable pointant vers ce corps -En Python, il est assez fréquent d'utiliser de code tel que celui-ci, souvent avec un dictionnaire: +En Python, il est assez fréquent d'utiliser de code tel que celui-ci, souvent avec un dictionnaire:: + + fonctions_connues = { + "français": dire_bonjour_en_français, + "anglais": dire_bonjour_en_anglais, + } + + # Ici on stocke la langue parlée par l'utilisateur + # et son prénom + langue_parlée = ... + prénom = .... + + if langue_parlée in fonctions_connues: + fonction = fonctions_connues[langue_parlée] + fonction(prénom) + Fonctions en tant qu'argement d'autres fonctions ------------------------------------------------ @@ -89,13 +104,41 @@ Fonctions imbriquées On peut aussi définir une fonction dans une autre fonction:: - TODO + + def affiche_message(message): + def affiche(): + print(message) + + affiche_message("Bonjour") + # affiche: Bonjour + +Deux notes importantes: + +Premièrement, la fonction `affiche()` qui est imbriquées dans `affiche_message()` n'est pas +accessible à l'éxtérieur de la fonction qui la contient. En d'autres termes, ce code +ne fonctionne pas:: + + def affiche_message(message): + def affiche(): + print(message) + + affiche() + # NameError: 'affiche' is not defined + +C'est un mécanisme similaire aux :ref:`portées des variables ` vu précédemment. + +Deuxièment, la fonction `affiche()` à l'intérieur de `affiche_message()` +a accès à l'argument `message` de la fonction `affiche_message`. On appelle +ça une "closure". + Fonctions retournant des fonctions ---------------------------------- -Enfin, on peut retourner une fonction depuis une autre fonction:: +En réalité, on combine souvent les closures avec des fonctions qui +retournent d'autres fonctions:: + def fabrique_fonction_qui_additionne(n): def fonction_résultat(x): @@ -114,4 +157,8 @@ Un autre paradigme Le fait qu'on puisse traiter les fonctions comme n'importe quelle autre valeur (c'est-à-dire les assigner à des variables, les passer -en argument et les retourner) +en argument et les retourner), est caractéristique des langages +dits "fonctionnels". Python est donc **à la fois** un +langages *impératif*, *objet* et *fonctionnel*. On dit que +c'est un langage *multi-paradigme*. + diff --git a/cours/source/19-functions-02/02-décorateurs.rst b/cours/source/19-functions-02/02-décorateurs.rst index d209bdd..a21cf34 100644 --- a/cours/source/19-functions-02/02-décorateurs.rst +++ b/cours/source/19-functions-02/02-décorateurs.rst @@ -1,23 +1,73 @@ -Fonctions en tant qu'argement d'autres fonctions -================================================ +Décorateurs +============ -On a vu en début de chapitre qu'on peut créé des variables qui pointent -vers des fonctions. +Définition +------------ -Du coup, rien n'empêche de les passer en *argument* d'autres fonctions. +Un décorateur est une fonction qui *enveloppe* une autre fonction. -Par exemple:: +On place le nom du décorateur avec une arobase (``@``) au-dessus +de la fonction décorée:: - def appelle_deux_fois(f): - f() - f() + def mon_décorateur(fonction): + def fonction_retournée(): + # fais quelque chose avec fonction + return fonction_retournée + @mon_décorateur + def ma_fonction_décorée(un_argument): + fais_un_truc_avec(un_argument) - def crier(): - print("Aline !") +Les deux dernières lignes sont équivalentes à:: - appelle_deux_fois(crier) + def ma_fonction_décorée(un_argument): + fais_un_truc_avec(un_argument) - # Affiche: - # Aline ! - # Aline ! + ma_fonction_décorée = mon_décorateur(ma_fonction_décorée) + + +Exemples de décorateurs +----------------------- + +On peut faire un décorateur qui nous empêche +d'appeler une fonction sous certaines conditions:: + + def pas_pendant_la_nuit(fonction): + def résultat(): + if il_fait_nuit: + print("chut") + else: + fonction() + return résultat + + @pas_pendant_la_nuit + def dire_bonjour(): + print("bonjour") + + il_fait_nuit = True + dire_bonjour() + # afiche: "chut" + +Décorateur prenant des arguments +-------------------------------- + +On peut aussi avoir des arguments passés aux décorateurs. Dans ce cas, on a besoin de +*trois* fonctions imbriquées. En effet, il nous faut une fonction pour traiter l'argument +``message`` et une autre pour traiter l`argument ``fonction``:: + + def affiche_message_avant_appel(message): + def décorateur(fonction): + def résultat(): + print(message) + fonction() + return résultat + return décorateur + + @affiche_message_avant_appel("dire_bonjour est appelée") + def dire_bonjour(): + print("bonjour") + + dire_bonjour() + # affiche: + # dire_bonjour est appelée + # bonjour diff --git a/cours/source/19-functions-02/index.rst b/cours/source/19-functions-02/index.rst index b9e086d..5eef30c 100644 --- a/cours/source/19-functions-02/index.rst +++ b/cours/source/19-functions-02/index.rst @@ -5,8 +5,4 @@ Chapitre 19 - Décorateurs :maxdepth: 1 01-introduction - - - - - + 02-décorateurs