Maison  >  Article  >  développement back-end  >  Une brève analyse de plusieurs concepts de syntaxe avancés de Python (décorateur de fermeture d'expression lambda)

Une brève analyse de plusieurs concepts de syntaxe avancés de Python (décorateur de fermeture d'expression lambda)

高洛峰
高洛峰original
2017-01-23 14:38:461486parcourir

1. Fonction anonyme
La fonction anonyme fait référence à une fonction qui n'est liée à aucun identifiant. Elle est principalement utilisée dans le domaine des langages de programmation fonctionnels :
1) Passée en paramètre. Les fonctions d'ordre supérieur (fonction d'ordre supérieur), telles que les fonctions intégrées filter/map/reduce en python sont toutes des fonctions typiques d'ordre supérieur
2) comme valeur de retour de la fonction d'ordre supérieur (bien que le "valeur" ici est en fait C'est un objet fonction)
Par rapport aux fonctions nommées, les fonctions anonymes sont syntaxiquement plus légères si la fonction n'est appelée qu'une seule fois ou un nombre limité de fois.
En termes de syntaxe spécifique, python prend en charge les fonctions anonymes dont le corps de fonction est une expression via la syntaxe lambda, c'est-à-dire : l'expression lambda de python est essentiellement une fonction anonyme, mais son corps de fonction ne peut être qu'une expression et ne peut pas contenir d'autres instructions.
De plus, les langages dynamiques de haut niveau utilisent souvent des fonctions anonymes pour implémenter une syntaxe avancée telle que des fermetures ou des décorateurs.
Dans certains cas, l'utilisation d'expressions lambda donne aux programmes Python un aspect très concis. Par exemple, ce qui suit est un exemple de code pour trier les éléments dict en fonction de leur valeur :

>>> foo = {'father' : 65, 'mother' : 62, 'sister' : 38, 'brother' : 29, 'me' : 28}
>>> sorted(foo.iteritems(), key=lambda x: x[1])
[('me', 28), ('brother', 29), ('sister', 38), ('mother', 62), ('father', 65)]

2. Fermeture
Une fermeture est essentiellement un environnement de référence qui contient ses fonctions ou références de fonction, la "référence". environnement" ici est généralement maintenu par une table qui stocke les références aux variables non locales auxquelles le corps de la fonction accède.
Par rapport aux pointeurs de fonction en langage C, les fermetures permettent aux fonctions imbriquées d'accéder à des variables non locales en dehors de leur portée, ce qui est lié aux règles de recherche de portée de l'interpréteur Python pour les variables (Python prend en charge les règles de recherche de LEGB, si vous souhaitez en savoir plus , vous pouvez vous référer à l'explication détaillée de la portée et des règles de recherche dans le chapitre 17 de "Learning Python" 4e édition, ou consulter cet article pour une compréhension rapide).
Pour les langages dont le modèle d'allocation de mémoire d'exécution crée des variables locales sur une pile linéaire (généralement comme le langage C), il est généralement difficile de prendre en charge les fermetures. Parce que dans l'implémentation sous-jacente de ces langages, si la fonction retourne, les variables locales définies dans la fonction seront détruites au fur et à mesure du recyclage de la pile de fonctions. Cependant, l'implémentation sous-jacente des fermetures nécessite que les variables non locales auxquelles elles souhaitent accéder restent valides lorsque la fermeture est exécutée jusqu'à la fin du cycle de vie de la fermeture. Cela signifie que ces variables non locales ne sont accessibles que lorsqu'elles sont déterminées. pour ne plus être accessibles. Elles ne peuvent être détruites que lorsqu'elles sont utilisées, et non lors du retour de la fonction qui définit ces variables. Par conséquent, les langages qui prennent naturellement en charge les fermetures utilisent généralement le garbage collection pour gérer la mémoire, car le mécanisme gc garantit que les variables seront détruites par le système et que leur espace mémoire ne sera récupéré que lorsqu'elles ne seront plus référencées.
En termes de syntaxe spécifique, les fermetures sont généralement accompagnées de définitions de fonctions imbriquées. En prenant Python comme exemple, un exemple de fermeture simple est le suivant :

#!/bin/env python
#-*- encoding: utf-8 -*-
 
def startAt_v1(x):
 def incrementBy(y):
  return x + y 
 print 'id(incrementBy)=%s' % (id(incrementBy))
 return incrementBy
 
def startAt_v2(x):
 return lambda y: x + y 
 
if '__main__' == __name__:
 c1 = startAt_v1(2)
 print 'type(c1)=%s, c1(3)=%s' % (type(c1), c1(3))
 print 'id(c1)=%s' % (id(c1))
  
 c2 = startAt_v2(2)
 print 'type(c2)=%s, c2(3)=%s' % (type(c2), c2(3))

Le résultat de l'exécution est le suivant :

id(incrementBy)=139730510519782
type(c1)=<type &#39;function&#39;>, c1(3)=5
id(c1)=139730510519782
type(c2)=<type &#39;function&#39;>, c2(3)=5

Dans l'exemple ci-dessus, startAt_v1 et startAt_v2 implémentent tous deux les fermetures , où : v1 est implémenté à l'aide de fonctions de définition imbriquées ; v2 est implémenté à l'aide d'expressions lambda/fonctions anonymes.
Nous prenons v1 comme exemple pour illustrer la fermeture :
1) La fonction startAt_v1 accepte 1 paramètre et renvoie un objet fonction, et le comportement de cet objet fonction est implémenté par la fonction définie imbriquée incrémentBy.
2) Pour la fonction incrémentBy, la variable x est une variable dite non locale (car x n'est ni une variable locale définie par la fonction ni une variable globale au sens ordinaire incrémentBy implémente un comportement de fonction spécifique et). revient.
3) La valeur de retour reçue par c1 à l'entrée principale est un objet fonction. De id(incrementBy) == id(c1), on peut conclure que l'objet "pointé vers" par c1 et l'objet "pointé vers" to" par le nom de fonction incrémentBy sont en fait le même objet de fonction.
4) Bénéficiant de la prise en charge des fermetures par Python, par rapport aux objets des fonctions ordinaires, l'objet pointé par c1 peut accéder à des variables non locales qui ne sont pas dans le cadre de sa fonction, et cette variable est la fonction wrapper externe de incrémentBy fourni par les paramètres d'entrée de startAt_v1. Par conséquent, l'objet fonction pointé par c1 a une fonction "mémoire" pour les paramètres d'entrée de sa fonction d'emballage externe. Lors de la création d'une fermeture en appelant la fonction d'emballage externe, différents paramètres d'entrée sont utilisés. par la fonction interne. Maintenu comme environnement de référence.
5) Lors de l'appel de c1(3), les paramètres entrants sont calculés avec les paramètres de la fonction d'emballage extérieur qui font référence à la maintenance de l'environnement pour obtenir le résultat final.
L'analyse des étapes ci-dessus illustre le principe de base d'une clôture de la création à l'exécution. Après avoir compris ce cas, le concept de clôture doit également être clair.

3. Décorateur
Python prend en charge la syntaxe du décorateur. Le concept de décorateurs est relativement obscur pour les débutants car il implique plusieurs concepts de programmation fonctionnelle (comme les fonctions anonymes et les fermetures). C'est pourquoi cet article présente d'abord les fonctions anonymes et les fermetures.

我们引用这篇文章对装饰器的定义:
A decorator is a function that takes a function object as an argument, and returns a function object as a return value.
从这个定义可知,装饰器本质上只是一个函数,它借助闭包的语法去修改一个函数(又称被装饰函数)的行为,即decorator其实是个闭包函数,该函数以被装饰函数名(这个函数名其实是一个函数对象的引用)作为入参,在闭包内修改被装饰函数的行为后,返回一个新的函数对象。
特别说明:decorator并非必须以函数形式出现,它可以是任何可被调用的对象,例如它也可以class形式出现,参见这篇文章给出的例子。
在定义好函数装饰器的前提下,当外部调用这个被装饰函数时,decorator的语法糖会由Python解释器解释为先执行装饰器函数,然后在装饰器返回的新函数对象上继续执行其余语句。
来个实例分析一下:

#!/bin/env python
#-*- encoding: utf-8 -*-
 
def wrapper(fn):
 def inner(n, m):
  n += 1
  print &#39;in inner: fn=%s, n=%s, m=%s&#39; % (fn.__name__, n, m)
  return fn(n, m) + 6 // 这里有return且返回值为int对象
 return inner
 
@wrapper
def foo(n, m):
 print &#39;in foo: n=%s, m=%s&#39; % (n, m)
 return n * m
 
print foo(2, 3)

上面的示例中,foo通过@wrapper语法糖声明它的装饰器是wrapper,在wrapper中,定义了嵌套的inner函数(该函数的参数列表必须与被装饰函数foo的参数列表保持一致),装饰器wrapper修改foo的行为后,返回inner(注意:由于inner的返回值是个int对象,故wrpper最终返回的也是个int对象)。
调用foo(2, 3)时,Python解释器先调用wrapper对foo做行为改写,然后返回int对象,不难推测,上述代码的执行结果如下:

in inner: fn=foo, n=3, m=3
in foo: n=3, m=3
foo(2, 3)=15

更多Python的几个高级语法概念浅析(lambda表达式闭包装饰器)相关文章请关注PHP中文网!

Déclaration:
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