首页 > 编程 > Python > 正文

基于Python闭包及其作用域详解

2020-02-16 02:08:53
字体:
来源:转载
供稿:网友

关于Python作用域的知识在python作用域有相应的笔记,这个笔记是关于Python闭包及其作用域的详细的笔记

如果在一个内部函数里,对一个外部作用域(但不是全局作用域)的变量进行引用,那么内部函数就被称为闭包(closure),而这个被内部函数引用的变量则被成为自由变量

闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量

命名空间和作用域

我们把命名空间看做一个大型的字典类型(Dict),里面包含了所有变量的名字和值的映射关系。在 Python 中,作用域实际上可以看做是“在当前上下文的位置,获取命名空间变量的规则”。在 Python 代码执行的任意位置,都至少存在三层嵌套的作用域:

最内层作用域,最先搜索,包含所有局部变量(Python 默认所有变量声明均为局部变量)

所有包含当前上下文的外层函数的作用域,由内而外依次搜索,这里包含的是非局部也非全局的变量

一直向上搜索,直到当前模块的全局变量

最外层,最后搜索的,内置(built-in)变量

 scopes = { "local": {"locals": None,    "non-local": {"locals": None,       "global": {"locals": None,         "built-in": ["built-ins"]}}},}

除了默认的局部变量声明方式,Python还有global和nonlocal两种类型的声明(nonlocal是Python3.x之后才有的),其中nonlocal是指最内层之外,global以内的变量。必须强调的是,最内层局部作用域对外层作用域的变量只有只读(read-only)的访问权限。比如下列的例子

x = 100def main(): x += 1 print (x)main()
UnboundLocalError Traceback (most recent call last)<ipython-input-2-9ed43e483a17> in <module>()  3 x += 1  4 print(x)----> 5 main()<ipython-input-2-9ed43e483a17> in main()  1 x = 100  2 def main():----> 3 x += 1  4 print(x)  5 main()UnboundLocalError: local variable 'x' referenced before assignment

这里抛出UnboundLocalError,是因为main()函数内部的作用域对于全局变量x仅有只读权限,想要在main()中对x进行改变,不会影响全局变量,而是会创建一个新的局部变量,显然无法对还未创建的局部变量直接使用x += 1, 因为x未绑定到任何对象上。如果想要获得全局变量的完全引用,则需要global声明:

x = 100def main(): global x x += 1 print(x)main()print(x) # 全局变量已被改变# result: # 101# 101

闭包

闭包和函数调用没多少相关,而是关于使用定义在其他作用域的变量。

看了上面的Python作用域规则后,我们可以仿照JavaScript写一个计数器的闭包:

"""/* JavaScript Closure example */var inc = function(){  var x = 0; return function(){ console.log(x++); };};var inc1 = inc()var inc2 = inc()"""# Pythondef inc(): x = 0 def inner():  nonlocal x  x += 1  print(x) return innerinc1 = inc()inc2 = inc()inc1()inc1()inc1()inc2()# result:# 1# 2# 3# 1            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表