English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Manuel de référence Python
Variable non locale dans une fonction imbriquée
Une fonction définie à l'intérieur d'une autre fonction est appelée fonction imbriquée. Une fonction imbriquée peut accéder aux variables de la portée fermée.
Dans Python, par défaut, ces variables non locales sont lecture-seule et nous devons les déclarer explicitement comme non locales (en utilisantmot-clé nonlocal) pour pouvoir les modifier.
Voici un exemple de fonction imbriquée accédant à des variables non locales.
def print_msg(msg): # C'est la fonction fermée externe def printer(): # C'est une fonction imbriquée print(msg) printer() # Nous exécutons cette fonction # Sortie: Hello print_msg("Hello")
Nous pouvons voir que la fonction imbriquée printer() peut accéder aux variables non locales de la fonction ferméemsg.
Que se passe-t-il si la dernière ligne de la fonction print_msg() retourne la fonction printer() plutôt que de l'appeler ? Cela signifie que la définition de la fonction est la suivante.
def print_msg(msg): # C'est la fonction fermée externe def printer(): # C'est une fonction imbriquée print(msg) return printer # Cela a changé # Essayons d'appeler cette fonction maintenant. # Sortie: Hello another = print_msg("Hello") another()
C'est inhabituel.
La fonction print_msg() est appelée avec une chaîne, "Hello" renvoie une fonction liée àAutreNom. Lorsque l'on appelle another(), bien que nous ayons terminé l'exécution de la fonction print_msg(), le message est toujours mémorisé.
Cette technique qui ajoute des données ("Hello") à du codedans PythonnomméeFermeture.
Même si la variable dépasse de sa plage ou que la fonction elle-même a été supprimée de l'espace de nom actuel, cette valeur dans la portée fermée est toujours mémorisée.
Tentez d'exécuter la commande suivante 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
From the above example, we can see that in Python, when a nested function refers to a value in its enclosed scope, we have a closure.
The following points summarize the conditions that must be met to create closures in Python.
We must have a nested function (function inside a function).
The nested function must refer to values defined in the enclosed function.
The enclosed function must return an nested function.
So, what is the use of closures?
Closures can avoid using global values and provide some form of data hiding. It can also provide an object-oriented solution to the problem.
When there are few methods implemented in a class (most of the time it is a single method), closure can provide another more elegant solution. However, when the number of properties and methods increases, it is best to implement a class.
This is a simple example where closure may be more preferable than defining a class and creating an object.
def make_multiplier_of(n): def multiplier(x): return x * n return multiplier # 3multiplier times3 = make_multiplier_of(3) # 5multiplier times5 = make_multiplier_of(5) # Output: 27 print(times3(9)) # Output: 15 print(times5(3)) # Output: 30 print(times5(times3(2))
Python decorators alsoA large number of closures are used.
Finally, it is best to point out that you can find the values enclosed in the enclosed function.
All function objects have a __closure__ attribute, if it is a closure function, then this attribute returns a tuple of cell objects. Refer to the example above, we know that times3and times5It is a closure function.
>>> make_multiplier_of.__closure__ >>> times3__closure__ (<cell at 0x0000000002D155B8: int object at 0x000000001E39B6E0>,)
The cell object has an attribute cell_contents that stores closed values.
>>> times3__closure__[0].cell_contents 3 >>> times5__closure__[0].cell_contents 5