fermeture
Il existe de nombreux articles présentant les fermetures Python sur Internet. Cet article découvrira les fermetures en résolvant un problème d'exigence.
Cette exigence est la suivante : nous devons continuer à enregistrer notre temps d'étude en minutes. C'est comme si j'étudiais pendant 2 minutes, j'en revenais 2. Puis après un moment, j'étudiais pendant 10 minutes, puis j'en revenais 12. Le temps d'apprentissage s'accumule ainsi.
Face à cette demande, nous créons généralement une variable globale pour enregistrer le temps, puis utilisons une méthode pour additionner chaque temps d'apprentissage. Habituellement, elle s'écrit sous la forme suivante :
time = 0 def insert_time(min): time = time + min return time print(insert_time(2)) print(insert_time(10))
Réfléchissez bien, y a-t-il quelque chose qui se passe. allumé ? Quel est le problème ?
En fait, cela signalera une erreur dans Python. L'erreur suivante sera signalée :
UnboundLocalError: local variable 'time' referenced before assignment
C'est parce que, en Python, si une fonction utilise le même nom qu'une variable globale et change la valeur de la variable, alors la variable deviendra une variable locale, ce qui entraînera fonction sans la définir, cette erreur sera donc signalée.
Si vous souhaitez vraiment référencer une variable globale et la modifier dans une fonction, que devez-vous faire ?
Nous pouvons utiliser le mot-clé global, et les modifications spécifiques sont les suivantes :
time = 0 def insert_time(min): global time time = time + min return time print(insert_time(2)) print(insert_time(10))
Le résultat de sortie est le suivant :
2 12
Mais, les variables globales sont utilisées ici Nous devons éviter autant que possible d'utiliser des variables globales pendant le développement. . Étant donné que différents modules et fonctions peuvent accéder librement aux variables globales, celles-ci peuvent être imprévisibles. Par exemple, le programmeur A modifie la valeur de la variable globale time, puis le programmeur B modifie également l'heure. S'il y a une erreur, il est difficile de la trouver et de la corriger.
Les variables globales réduisent la polyvalence entre les fonctions ou les modules. Différentes fonctions ou modules dépendent de variables globales. De même, les variables globales réduisent la lisibilité du code et les lecteurs peuvent ne pas savoir qu'une certaine variable appelée est une variable globale.
Y a-t-il une meilleure façon ?
À l'heure actuelle, nous utilisons des fermetures pour résoudre le problème. Tout d'abord, regardez directement le code :
time = 0 def study_time(time): def insert_time(min): nonlocal time time = time + min return time return insert_time f = study_time(time) print(f(2)) print(time) print(f(10)) print(time)
Les résultats de sortie sont les suivants :
2 0 12 0
La manifestation la plus directe ici est que la variable globale time n'a pas été modifiée. jusqu'à présent, et la clé non locale est toujours utilisée ici Word, indiquant l'utilisation de variables externes (non globales) dans des fonctions ou d'autres portées. Alors, quel est le processus d’exécution spécifique du code ci-dessus. Nous pouvons regarder l'image ci-dessous :
Ce type de comportement dans lequel les variables dans la portée locale de la fonction externe sont accessibles dans la portée locale de la fonction interne est appelé : fermeture. Une façon plus directe de l'exprimer est que lorsqu'une fonction est renvoyée en tant qu'objet, des variables externes sont incluses, formant une fermeture. k
Les fermetures évitent l'utilisation de variables globales. De plus, les fermetures permettent d'associer une fonction à certaines données (environnement) sur lesquelles elle opère. Et l'utilisation de fermetures peut rendre le code plus élégant. Et les décorateurs mentionnés dans le prochain article sont également mis en œuvre sur la base de fermetures.
À ce stade, il y aura une question. Pensez-vous qu'il s'agit d'une fermeture ou d'une fermeture ? Existe-t-il un moyen de vérifier que cette fonction est une fermeture ?
Oui, toutes les fonctions ont un attribut __closure__. Si la fonction est une fermeture, alors elle renvoie un objet tuple composé de cellules. La propriété cell_contents de l'objet cellule est la variable stockée dans la fermeture.
Imprimons-le et expérimentons-le :
time = 0 def study_time(time): def insert_time(min): nonlocal time time = time + min return time return insert_time f = study_time(time) print(f.__closure__) print(f(2)) print(time) print(f.__closure__[0].cell_contents) print(f(10)) print(time) print(f.__closure__[0].cell_contents)
Le résultat imprimé est :
(<cell at 0x0000000000410C48: int object at 0x000000001D6AB420>,) 2 0 2 12 0 12
Il ressort du résultat de l'impression que la valeur transmise est toujours stockée dans le cell_contents de la fermeture. Par conséquent, c'est le plus grand. fonctionnalité de la fermeture. Vous pouvez Les variables de la fonction parent sont liées aux fonctions qui y sont définies. Même si la fonction parent qui a généré la fermeture a été libérée, la fermeture existe toujours.
Le processus de fermeture est en fait comme une classe (fonction parent) générant une instance (fermeture). La différence est que la fonction parent n'est exécutée que lorsqu'elle est appelée, et son environnement sera libéré après l'exécution, tandis que la classe est créée lorsque. le fichier est exécuté.GénéralementLa portée est libérée après l'exécution du programme.Par conséquent, pour certaines fonctions qui doivent être réutilisées et ne suffisent pas à être définies comme comportements d'une classe, l'utilisation de fermetures occupera moins de ressources que l'utilisation de classes. est plus léger et flexible.