Maison > Article > développement back-end > Compréhension approfondie du mécanisme de fermeture de Python
Cet article utilise Python comme exemple pour expliquer les fermetures de manière simple ; selon l'Encyclopédie Baidu, une fermeture est une fonction qui peut lire les variables internes d'autres fonctions. Par exemple, en JavaScript, uniquement les sous-fonctions à l'intérieur du. la fonction peut lire les variables locales. Par conséquent, la fermeture peut être comprise comme « une fonction définie à l'intérieur d'une fonction » ; en substance, la fermeture est le pont qui relie l'intérieur de la fonction à l'extérieur de la fonction
Définition : Une fermeture est une fonction qui peut lire les variables internes de autres fonctions
Compréhension : D'après l'analyse de l'instruction fractionnée, la fermeture est... une fonction. Il s'avère que la fermeture est une fonction. dans les détails pour voir de quel type de fonction il s'agit. La fermeture peut également être lue pour obtenir les variables internes d'autres fonctions. En d'autres termes, la fonction de fermeture peut obtenir les informations sur les variables internes d'autres fonctions - de cette manière, l'information est encapsulée, comme un paquet, ce qui est plus vivant
Exemple :
def make_averager(): series = [] def averager(new_value): series.append(new_value) total = sum(series) return total/len(series) return averager
>>> avg = make_averager()>>> avg(10)10.0>>> avg(11)10.5>>> avg(12)11.0
Remarque : la fermeture est l'abréviation de fermeture lexicale. C'est une structure grammaticale importante de la programmation fonctionnelle
En C++, il existe un mot-clé spécial (espace de noms en anglais) namespace
Ne parlons pas de C++, en Python , il y a quatre espaces de noms :
1) : variables locales local namespace
2) : Variables des fonctions externes dans les fonctions imbriquées (Python3.x) nonlocal namespace
3) : Variables globales global namespace
4) : Variables intégrées build-in namespace
namespace est un mappage de noms de variables avec des objets réels, la plupart des espaces de noms sont implémentés sous forme de dictionnaires en Python. Le mot-clé
a été introduit dans Python 3.0. Utilisez ce mot-clé pour accéder et modifier facilement les variables externes des fonctions imbriquées (si vous accédez uniquement sans modification, vous n'avez pas besoin du mot-clé nonlocal) nonlocal
Si vous modifiez les variables externes Cependant, si vous n'utilisez pas le mot clé , une erreur sera signalée : nonlocal
def make_averager(): count = 0 total = 0 def averager(new_value): count += 1 # Same as: count = count + 1 total += new_value return total/count return average
>>> avg = make_averager() >>> avg(10) Traceback (most recent call last):...UnboundLocalError: Local variable 'count' referened before assignment >>>
Pour modifier la variable externe, vous devez utiliser le mot-clé : nonlocal
def make_averager(): count = 0 total = 0 def averager(new_value): nonlocal count, total # Declaration of namespace. count += 1 total += new_value return total/count return average
>>> avg = make_averager()>>> avg(10)10.0>>> avg(11)10.5>>> avg(12)12
Explication : Dans la fonction moyenneur, le nombre et le total sont des variables libres (Les variables libres font référence à celles qui ne sont pas liées localement aux variables ), les variables libres sont souvent déclarées dans une portée et utilisées dans une autre portée (comme la série, le nombre, le total ci-dessus)
Alors pourquoi dans l'exemple de « Comprendre la définition de la fermeture », bien que la variable série soit également une variable libre pour la fonction interne, elle peut être modifiée directement ? Ici, nous devons distinguer le sens de "modification" entre les types mutables et les types immuables. La liste des séries est une séquence mutable. La méthode consiste à modifier la valeur de la liste en place append()
. seulement La fonctionnalité de liste "variable de liste" est utilisée , mais pour le nombre d'objets numériques immuables, total, , une telle opération génère en fait un nouvel objet count += 1
Rappelez-vous toujours que les variables libres ne peuvent être référencées et non modifiées (à moins que les objets mutables puissent être modifiés sur place, en fait c'est comment les fermetures sont implémentées dans Python2 Fermetures et expressions lambda
L'expression lambda de Python est une fonction anonyme, et les deux peuvent. être égal
Fermetures et décorateurs
Pour implémenter votre propre décorateur en Python, vous devez maîtriser les connaissances : 1) Fermeture + fonction imbriquée, 2) mot-clé non local (introduit dans Python3.x)
""" Implement a decorator, which return the runtime of the program. """import timedef clock(func): def clocked(*args): t0 = time.pref_counter() result = func(*args) elapsed = time.pref_counter() - t0 name = func.__name__ arg_str = ', '.join(repr(arg) for arg in args) print('[%0.8fs] %s(%s) -> %r' %(elpased, name, arg_str, result)) return result return clocked
本文以Python为例,深入浅出讲解闭包;根据百度百科的解释,闭包就是能够读取其他函数内部变量的函数,例如在JavaScript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成『定义在一个函数内部的函数』;在本质上,闭包是将函数内部和函数外部连接起来的桥梁
定义:闭包(closure)是能够读取其它函数内部变量的函数
理解:根据拆分语句分析,闭包是……函数,原来闭包是函数,再看细节部分,闭包是怎样的函数,闭包还能够读取其它函数内部变量,换句话说,闭包函数可以获取其它函数内部变量的信息——这样信息就被封装起来了,像一个包一样,比较形象
实例:
def make_averager(): series = [] def averager(new_value): series.append(new_value) total = sum(series) return total/len(series) return averager
>>> avg = make_averager()>>> avg(10)10.0>>> avg(11)10.5>>> avg(12)11.0
备注:闭包(closure)是词法闭包(lexical closure)的简称,是函数式编程的重要的语法结构
在C++中,有个专门的关键字namespace
(命名空间的英文)
不扯C++,在Python中,存在四种命名空间:
1)local namespace
:本地变量
2)nonlocal namespace
:嵌套函数中外层函数的变量(Python3.x)
3)global namespace
:全局变量
4)build-in namespace
:内置变量
namespace是变量名到实际对象的一个映射,大部分namespace都是按Python中的字典来实现的
nonlocal
关键字在Python3.0中被引入,使用这个关键字可以轻松的访问并修改嵌套函数的较外层变量(如果仅仅是访问而不修改可以不用nonlocal关键字)
如果修改外层变量却不使用nonlocal
关键字会报错:
def make_averager(): count = 0 total = 0 def averager(new_value): count += 1 # Same as: count = count + 1 total += new_value return total/count return average
>>> avg = make_averager() >>> avg(10) Traceback (most recent call last):...UnboundLocalError: Local variable 'count' referened before assignment >>>
要修改外层变量就必须使用nonlocal
关键字:
def make_averager(): count = 0 total = 0 def averager(new_value): nonlocal count, total # Declaration of namespace. count += 1 total += new_value return total/count return average
>>> avg = make_averager()>>> avg(10)10.0>>> avg(11)10.5>>> avg(12)12
解释:在averager函数中,count、total是自由变量(自由变量是指未在本地绑定的变量),自由变量往往是在一个作用域中声明,并在另一个作用域中使用(比如上面的series、count、total)
那为什么在『理解闭包的定义』的实例中,series变量虽然对于内层函数也是自由变量但是却可以直接修改?这里要区分开可变类型和不可变类型的『修改』的含义,series列表是可变序列,append()
方法于在原地修改列表的值,这里我们只用到了『列表可变』这一列表的特性,但是对于不可变的数字对象count、total,count += 1
,这样的操作实际上生成了新的对象
始终记住,自由变量只能引用不能修改(除非可变对象可以原地修改,事实上Python2.x中就是这样实现闭包的),要修改就必须使用nonlocal关键字
Python的lambda表达式就是匿名函数,二者可以划等号
出于演示考虑,用for循环或者Pythonic的列表推导是个不错的选择:
要在Python中实现自己的装饰器(decorator),必须掌握的知识:1)闭包+嵌套函数,2)nonlocal关键字(Python3.x引入)
""" Implement a decorator, which return the runtime of the program. """import timedef clock(func): def clocked(*args): t0 = time.pref_counter() result = func(*args) elapsed = time.pref_counter() - t0 name = func.__name__ arg_str = ', '.join(repr(arg) for arg in args) print('[%0.8fs] %s(%s) -> %r' %(elpased, name, arg_str, result)) return result return clocked
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!