Fermetures Python
Fermetures Python
Dans ce didacticiel, vous découvrirez la fermeture Python, comment définir une fermeture et les raisons pour lesquelles vous devriez l'utiliser.
Variable non locale dans une fonction imbriquée
Avant d'entrer dans ce qu'est une fermeture, nous devons d'abord comprendre ce qu'est une fonction imbriquée et une variable non locale.
Une fonction définie à l'intérieur d'une autre fonction est appelée une fonction imbriquée. Les fonctions imbriquées peuvent accéder aux variables de la portée englobante.
En Python, ces variables non locales sont en lecture seule par défaut et nous devons les déclarer explicitement comme non locales (en utilisant le mot-clé nonlocal) afin de les modifier.
Voici un exemple de fonction imbriquée accédant à une variable non locale.
def print_msg(msg):
# This is the outer enclosing function
def printer():
# This is the nested function
print(msg)
printer()
# We execute the function
# Output: Hello
print_msg("Hello")
Sortie
Hello
Nous pouvons voir que le printer()
imbriqué la fonction a pu accéder au msg non local variable de la fonction englobante.
Définir une fonction de fermeture
Dans l'exemple ci-dessus, que se passerait-il si la dernière ligne de la fonction print_msg()
a renvoyé le printer()
fonction au lieu de l'appeler? Cela signifie que la fonction a été définie comme suit :
def print_msg(msg):
# This is the outer enclosing function
def printer():
# This is the nested function
print(msg)
return printer # returns the nested function
# Now let's try calling this function.
# Output: Hello
another = print_msg("Hello")
another()
Sortie
Hello
C'est inhabituel.
Le print_msg()
la fonction a été appelée avec la chaîne "Hello"
et la fonction renvoyée était liée au nom un autre . Sur appel another()
, le message était toujours mémorisé bien que nous ayons déjà fini d'exécuter le print_msg()
fonction.
Cette technique par laquelle certaines données ("Hello
dans ce cas) est attaché au code est appelé fermeture en Python .
Cette valeur dans la portée englobante est mémorisée même lorsque la variable sort de la portée ou que la fonction elle-même est supprimée de l'espace de noms actuel.
Essayez d'exécuter ce qui suit dans le shell Python pour voir le résultat.
>>> del print_msg
>>> another()
Hello
>>> print_msg("Hello")
Traceback (most recent call last):
...
NameError: name 'print_msg' is not defined
Ici, la fonction renvoyée fonctionne toujours même lorsque la fonction d'origine a été supprimée.
Quand avons-nous des fermetures ?
Comme le montre l'exemple ci-dessus, nous avons une fermeture en Python lorsqu'une fonction imbriquée fait référence à une valeur dans sa portée englobante.
Les critères qui doivent être remplis pour créer une fermeture en Python sont résumés dans les points suivants.
- Nous devons avoir une fonction imbriquée (fonction à l'intérieur d'une fonction).
- La fonction imbriquée doit faire référence à une valeur définie dans la fonction englobante.
- La fonction englobante doit renvoyer la fonction imbriquée.
Quand utiliser les fermetures ?
Alors, à quoi servent les bouclages ?
Les fermetures peuvent éviter l'utilisation de valeurs globales et fournissent une certaine forme de masquage des données. Il peut également fournir une solution orientée objet au problème.
Lorsqu'il y a peu de méthodes (une méthode dans la plupart des cas) à implémenter dans une classe, les fermetures peuvent fournir une solution alternative et plus élégante. Mais lorsque le nombre d'attributs et de méthodes augmente, il est préférable d'implémenter une classe.
Voici un exemple simple où une fermeture peut être préférable à la définition d'une classe et à la création d'objets. Mais la préférence vous appartient.
def make_multiplier_of(n):
def multiplier(x):
return x * n
return multiplier
# Multiplier of 3
times3 = make_multiplier_of(3)
# Multiplier of 5
times5 = make_multiplier_of(5)
# Output: 27
print(times3(9))
# Output: 15
print(times5(3))
# Output: 30
print(times5(times3(2)))
Sortie
27 15 30
Les décorateurs Python font également un usage intensif des fermetures.
Pour conclure, il est bon de souligner que les valeurs qui sont incluses dans la fonction de fermeture peuvent être trouvées.
Tous les objets de fonction ont un __closure__
attribut qui renvoie un tuple d'objets cellule s'il s'agit d'une fonction de fermeture. En se référant à l'exemple ci-dessus, nous savons times3
et times5
sont des fonctions de fermeture.
>>> make_multiplier_of.__closure__
>>> times3.__closure__
(<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
L'objet cellule a l'attribut cell_contents qui stocke la valeur fermée.
>>> times3.__closure__[0].cell_contents
3
>>> times5.__closure__[0].cell_contents
5
Python