Browse Source

Fin du cours sur les décorateurs

master
Dimitri Merejkowsky 4 years ago
parent
commit
600b2b5f8a
4 changed files with 119 additions and 24 deletions
  1. +2
    -0
      cours/source/06-fonctions-01/02-portée-des-variables.rst
  2. +51
    -4
      cours/source/19-functions-02/01-introduction.rst
  3. +65
    -15
      cours/source/19-functions-02/02-décorateurs.rst
  4. +1
    -5
      cours/source/19-functions-02/index.rst

+ 2
- 0
cours/source/06-fonctions-01/02-portée-des-variables.rst View File

@@ -1,3 +1,5 @@
.. _portées-des-variables:

Portée des variables
====================



+ 51
- 4
cours/source/19-functions-02/01-introduction.rst View File

@@ -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 <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*.


+ 65
- 15
cours/source/19-functions-02/02-décorateurs.rst View File

@@ -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

+ 1
- 5
cours/source/19-functions-02/index.rst View File

@@ -5,8 +5,4 @@ Chapitre 19 - Décorateurs
:maxdepth: 1

01-introduction





02-décorateurs