Les fermetures en python sont définies (interprétées) de manière expressive comme suit : Si dans une fonction interne, une variable dans la portée externe (mais pas dans la portée globale) est référencée, alors la fonction interne est considérée comme une fermeture.
Les instructions suivantes concernent principalement python2.7, il peut y avoir des différences dans d'autres versions.
Peut-être que ce n'est pas clair si vous regardez directement la définition. Voyons d'abord ce que sont les fonctions internes :
def wai_hanshu(canshu_1):
def nei_hanshu(canshu_2): # 我在函数内部有定义了一个函数
return canshu_1*canshu_2
return nei_hanshu # 我将内部函数返回出去
a = wai_hanshu(123) # 此时 canshu_1 = 123
print a
print a(321) # canshu_2 = 321
Copier après la connexion
<🎜. >
J'ai une fonction imbriquée à l'intérieur de la fonction. Lorsque je passe une variable à la fonction externe et que je l'attribue à a, nous constatons que a devient un objet fonction, et je passe des paramètres à cela. à nouveau l'objet fonction, la valeur de retour de la fonction interne est obtenue. On sait que selon le principe de scope, on ne peut pas accéder au scope local dans le scope global. Cependant, les fonctions internes sont accessibles ici via une méthode délicate. .
Continuons à regarder un exemple :
def wai_hanshu():
a = []
def nei_hanshu(canshu):
a.append(canshu)
return a
return nei_hanshu
a = wai_hanshu()
print a(123)
print a(321)
Copier après la connexion
On voit que le La fonction se trouve dans la liste des fonctions externes et a été modifiée. Pour savoir pourquoi, vous devez d'abord savoir ce qu'est un espace de noms Python, et les espaces de noms sont la raison des performances de la portée. Ici, je vais vous expliquer brièvement.
La principale raison de l'introduction des espaces de noms est d'éviter les conflits de variables, car il existe de nombreux modules en python, et il y a des fonctions, des classes, etc. dans les modules, et ils utilisent tous des variables. Mais ce serait trop gênant si vous deviez faire attention à ne pas entrer en conflit avec d'autres noms de variables à chaque fois. Les développeurs devraient se concentrer sur leurs propres problèmes, plutôt que de réfléchir aux variables utilisées dans les programmes écrits par d'autres, c'est pourquoi Python a introduit les espaces de noms. L'espace de noms est divisé en couche de module, et le module est divisé en portée globale et portée locale S'il est représenté par un diagramme :
Les espaces de noms sont différents entre les modules, et là. sont également des portées globales et des portées locales peuvent également être imbriquées avant, afin de garantir que les noms de variables n'entrent pas en conflit. D'ailleurs, vous pouvez obtenir le nom de l'espace de noms via l'attribut __name__ :
L'espace de noms du fichier principal s'appelle '__main__', et l'espace de noms du module est le nom du module. La portée
est née parce que lorsque Python recherche une variable, il la recherchera d'abord dans l'espace de noms actuel. Si elle n'est pas trouvée dans l'espace de noms actuel, il la recherchera dans le niveau supérieur. espace de noms. Par analogie, s'il n'est pas trouvé à la fin, une exception de variable non trouvée sera déclenchée.
Nous l'avons toujours dit auparavant : le périmètre global ne peut pas accéder au périmètre local, mais le périmètre local peut accéder au périmètre global pour cette raison. Et lorsque je crée une variable dans la portée locale avec le même nom que l'extérieur, lorsque python recherche cette variable, il la recherchera d'abord dans la portée actuelle. Si elle est trouvée, il ne continuera pas à la chercher. un niveau plus haut.
Dans les premières versions de Python, les étendues locales ne pouvaient pas accéder aux autres étendues locales, mais ne pouvaient accéder qu'aux étendues globales. Cependant, dans les versions actuelles, elles sont recherchées un niveau plus haut dans l'ordre, je vais donc le mentionner ici.
Grâce à cette fonctionnalité, nous pouvons accéder aux variables de la fonction externe dans la fonction interne, ce qu'on appelle aussi la fermeture.
Remarque : Il est nécessaire de distinguer les objets ici, par exemple :
def wai_hanshu():
a = []
def nei_hanshu(canshu):
a.append(canshu)
return a
return nei_hanshu
a = wai_hanshu() # 我创建了一个对象
b = wai_hanshu() # 我又创建了一个对象
print a
print b
print a(123)
print b(321)
Copier après la connexion
Ici, bien que nous exploitions tous des variables dans wai_hanshu, a et b sont complètement deux objets, et les espaces mémoire où ils se trouvent sont également différents, donc les données à l'intérieur sont également indépendantes. Attention à ne pas mélanger les choses.
Décorateur
En fait, le décorateur fait quelques étapes supplémentaires en fonction de la fermeture Regardez le code :
<🎜. >
def zsq(func): # 装饰函数
def nei():
print '我在传入的函数执行之前做一些操作'
func() # 执行函数
print '我在目标函数执行后再做一些事情'
return nei
def login(): # 被装饰函数
print '我进行了登录功能'
login = zsq(login) # 我将被装饰的函数传入装饰函数中,并覆盖了原函数的入口
login() # 此时执行的就是被装饰后的函数了
Copier après la connexion
在看这段代码的时候,要知道几件事:
1.函数的参数传递的其实是引用,而不是值。
2.函数名也是一个变量,所以可以重新赋值。
3.赋值操作的时候,先执行等号右边的。
只有明白了上面这些事之后,再结合一下代码,应该就能明白什么是装饰器了。所谓装饰器就是在闭包的基础上传递了一个函数,然后覆盖原来函数的执行入口,以后调用这个函数的时候,就可以额外实现一些功能了。装饰器的存在主要是为了不修改原函数的代码,也不修改其他调用这个函数的代码,就能实现功能的拓展。
而python觉得让你每次都进行重命名操作实在太不方便,于是就给出了一个便利的写法:
def zsq(func):
def nei():
print '我在传入的函数执行之前做一些操作'
func() # 执行函数
print '我在目标函数执行后再做一些事情'
return nei
@zsq # 自动将其下面的函数作为参数传到装饰函数中去
def login():
print '我进行了登录功能'
login()
Copier après la connexion
这些小便利也叫做python的语法糖,你可能在很多地方见过这个说法。
带参数的装饰器:
def zsq(a):
print '我是装饰器的参数', a
def nei(func):
print '我在传入的函数执行之前做一些操作'
func() # 执行函数
print '我在目标函数执行后再做一些事情'
return nei
@zsq('123')
def login():
print '我进行了登录功能'
Copier après la connexion
相当于: login = zsq(123)(login) ,所以在这里没有调用就执行了。
装饰器的嵌套:
这里就不完整写个例子了:
@deco1(deco_arg)
@deco2
def func():
pass
Copier après la connexion
相当于: func = deco1(deco_arg)(deco2(func))
也就是从上到下的嵌套了。
关于闭包和装饰器就先讲到这里,以后有需要再补充。
以上这篇深入Comprendre les fermetures et les décorateurs en python就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持PHP中文网。
更多Comprendre les fermetures et les décorateurs en python相关文章请关注PHP中文网!