Fermetures Python: comment l'utiliser et pourquoi?

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 dans 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 un mot clé non local) 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")

Production

 Bonjour

Nous pouvons voir que la printer()fonction imbriquée a pu accéder à la variable msg non locale de la fonction englobante.

Définition d'une fonction de fermeture

Dans l'exemple ci-dessus, que se passerait-il si la dernière ligne de la fonction print_msg()renvoyait la 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()

Production

 Bonjour

C'est inhabituel.

La print_msg()fonction a été appelée avec la chaîne "Hello"et la fonction retournée était liée au nom d'un autre. Lors de l'appel another(), le message était toujours mémorisé bien que nous ayons déjà fini d'exécuter la print_msg()fonction.

Cette technique par laquelle certaines données ( "Hellodans ce cas) sont attachées au code est appelée 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 la sortie.

 >>> del print_msg >>> another() Hello >>> print_msg("Hello") Traceback (most recent call last):… NameError: name 'print_msg' is not defined

Ici, la fonction retourné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 fermetures?

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 pourrait être plus préférable que de définir une classe et de créer des 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)))

Production

 27 15 30

Les décorateurs Python utilisent également largement les fermetures.

Pour conclure, il est bon de souligner que les valeurs 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 de cellule s'il s'agit d'une fonction de fermeture. En se référant à l'exemple ci-dessus, nous connaissons times3et times5sommes des fonctions de fermeture.

 >>> make_multiplier_of.__closure__ >>> times3.__closure__ (,)

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

Articles intéressants...