Maison > développement back-end > Tutoriel Python > Comprendre les fermetures et les décorateurs en python

Comprendre les fermetures et les décorateurs en python

高洛峰
Libérer: 2017-03-03 13:58:01
original
1228 Les gens l'ont consulté

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

<🎜. >

Comprendre les fermetures et les décorateurs en python

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

Comprendre les fermetures et les décorateurs en python

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 :

Comprendre les fermetures et les décorateurs en python

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__ :

Comprendre les fermetures et les décorateurs en python

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

Comprendre les fermetures et les décorateurs en python

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 &#39;我在传入的函数执行之前做一些操作&#39;
    func() # 执行函数
    print &#39;我在目标函数执行后再做一些事情&#39;
  return nei

def login():  # 被装饰函数
  print &#39;我进行了登录功能&#39;

login = zsq(login)  # 我将被装饰的函数传入装饰函数中,并覆盖了原函数的入口

login()   # 此时执行的就是被装饰后的函数了
Copier après la connexion

在看这段代码的时候,要知道几件事:

1.函数的参数传递的其实是引用,而不是值。

2.函数名也是一个变量,所以可以重新赋值。

3.赋值操作的时候,先执行等号右边的。

只有明白了上面这些事之后,再结合一下代码,应该就能明白什么是装饰器了。所谓装饰器就是在闭包的基础上传递了一个函数,然后覆盖原来函数的执行入口,以后调用这个函数的时候,就可以额外实现一些功能了。装饰器的存在主要是为了不修改原函数的代码,也不修改其他调用这个函数的代码,就能实现功能的拓展。

而python觉得让你每次都进行重命名操作实在太不方便,于是就给出了一个便利的写法:

def zsq(func):
  def nei():
    print &#39;我在传入的函数执行之前做一些操作&#39;
    func() # 执行函数
    print &#39;我在目标函数执行后再做一些事情&#39;
  return nei

@zsq  # 自动将其下面的函数作为参数传到装饰函数中去
def login():
  print &#39;我进行了登录功能&#39;


login()
Copier après la connexion

Comprendre les fermetures et les décorateurs en python

这些小便利也叫做python的语法糖,你可能在很多地方见过这个说法。

带参数的装饰器:

def zsq(a):
  print &#39;我是装饰器的参数&#39;, a
  def nei(func):
    print &#39;我在传入的函数执行之前做一些操作&#39;
    func() # 执行函数
    print &#39;我在目标函数执行后再做一些事情&#39;
  return nei


@zsq(&#39;123&#39;)
def login():
  print &#39;我进行了登录功能&#39;
Copier après la connexion

Comprendre les fermetures et les décorateurs en python

相当于: 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中文网!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal