Python中闭包的理解
2017-04-24 17:04
302 查看
Python中闭包的理解:
Num01–>定义:
官方定义: 闭包是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。自已的理解为: 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
举一个简单的例子来说明:
def addx(x): def addy(y): return x + y return addy xy = addx(6) print(type(xy)) print(xy.__name__) print(xy(66)) # 结果是: # <class 'function'> # addy # 72
对以上代码加以说明:
如果在一个内部函数里:addy(y)就是这个内部函数。
对在外部作用域(但不是全局作用域)的变量进行引用:x就是被引用的变量,x在外部作用域addx(x)函数里,但不在全局作用域里。
那么这个内部函数addy(y)就是闭包。
闭包的_closure_属性
一个函数和它的环境变量合在一起,就构成了一个闭包(closure)。在Python中,所谓的闭包是一个包含有环境变量取值的函数对象。环境变量取值被保存在函数对象的_closure_属性中。如下案例加以说明:
b = 5 def line_func(): b = 55 def line(x): return 2 * x + b return line my_line = line_func() print(my_line.__closure__) print(my_line.__closure__[0].cell_contents) # 结果如下: # (<cell at 0x0000028F6E228C18: int object at 0x00000000508A0890>,) # 55
对以上代码加以说明:
_closure_里面包含了一个元组。元组中每一个对象类型都是cell类型的。元组中的第0个元素就是55,也就是创建闭包时的环境变量b的取值。
Num02–>为什么要使用闭包
不同的是闭包本身就是个方法。和类一样,我们在编程时经常会把通用的东西抽象成类,以复用通用的功能。闭包也是一样,当我们需要函数粒度的抽象时,闭包就是一个很好的选择。 在这点上闭包可以被理解为一个只读的对象,你可以给他传递一个属性,但它只能提供给你一个执行的接口。因此在程序中我们经常需要这样的一个函数对象——闭包,来帮我们完成一个通用的功能。
Num03–>使用闭包注意事项
Test01–>闭包中是不能修改外部作用域局部变量的值
看如下案例:def func(): m = 0 def func_in(): m = 1 print("++%d" % m) print("--%d" % m) func_in() print("==%d" % m) print("最后打印:%s" % func()) # 结果如下: # --0 # ++1 # ==0 # 最后打印:None
对以上代码加以说明:
从执行结果可以看出,虽然在闭包里面也定义了一个变量m,但是其不会改变外部函数中的局部变量m的值。
Test02–>局部变量的问题
def foo(): a = 1 def bar(): a = a + 1 return a return bar f=foo() print(f()) # 结果如下: # Traceback (most recent call last): # File "E:/pycharmProject/Test24.py", line 82, in <module> # print(f()) # File "E:/pycharmProject/Test24.py", line 77, in bar # a = a + 1 # UnboundLocalError: local variable 'a' referenced before assignment
以上代码加以说明:
这是因为在执行代码 f = foo()时,Python会导入全部的闭包函数体bar()来分析其的局部变量。Python规则指定所有在赋值语句左面的变量都是局部变量,则在闭包bar()中,变量a在赋值符号”=”的左面,被Python认为是bar()中的局部变量。再接下来执行print(f())时,程序运行至a = a + 1时,因为先前已经把a归为bar()中的局部变量,所以python会在bar()中去找在赋值语句右面的a的值,结果找不到,就会报错。
两种解决办法
#第一种解决办法:自由变量为不可变对象 def foo(): a = 1 def bar(): nonlocal a a = a + 1 return a return bar f=foo() print(f()) #第二种解决办法:不是太好,不建议,自由变量为可变对象 def foo(): a = [1] def bar(): a[0] = a[0] + 1 return a[0] return bar f=foo() print(f())
Test03–>Python函数式编程中一个问题
看如下代码:for a in range(10): print(i)
在程序里面经常会出现这类的循环语句,Python的问题就在于:当循环结束以后,循环体中的临时变量a不会销毁,而是继续存在于执行环境中。
还有一个Python的现象是:Python的函数只有在执行时,才会去找函数体里的变量的值。
listname = [] for a in range(3): print("a==%s" % a) def foo(x): print("a--%s" % a) print(x + a) print("a++%s" % a) listname .append(foo) for f in listname : f(2) # 看结果是: # a==0 # a==1 # a==2 # a--2 # 4 # a++2 # a--2 # 4 # a++2 # a--2 # 4 # a++2
可能有些人认为这段代码的执行结果应该是2,3,4.但是实际的结果是4,4,4。这是因为当把函数加入flist列表里时,Python还没有给a赋值,只有当执行时,再去找a的值是什么。这时在for循环语句中,已经将a的值赋值为2,所以以上代码的执行结果是4,4,4。
如果要想结果是2,3,4,看如下代码修改:
listname = [] for a in range(3): print("a==%s" % a) def foo(x, y=a): print("a==%s" % a) print("y--%s" % y) print(x + y) print("y++%s" % y) print("a==%s" % a) listname.append(foo) for f in listname: f(2) # 看结果是: # a==0 # a==1 # a==2 # a==2 # y--0 # 2 # y++0 # a==2 # a==2 # y--1 # 3 # y++1 # a==2 # a==2 # y--2 # 4 # y++2 # a==2
相信读者看到这里就能明白函数式编程的特点了。
Num04–>闭包的作用
作用1:当闭包执行完后,仍然能够保持住当前的运行环境。作用2:闭包可以根据外部作用域的局部变量来得到不同的结果。
作用3:闭包对数据的持久化以及按配置产生不同的功能,是很有帮助的
相关文章推荐
- Python:闭包的理解
- python函数里面的装饰器和闭包的理解
- python中的闭包以及对装饰器的理解
- python 闭包的理解
- 关于python中闭包的理解和小例子
- python 中闭包理解,及函数string.maketrans(),string.translate()
- Python闭包、函数式编程、装饰器深入理解
- python中闭包和装饰器的理解(关于python中闭包和装饰器解释最好的文章)。
- 理解python中的闭包
- python 装饰器、内部函数、闭包简单理解
- 关于Python闭包的理解
- python闭包(Closure),用地址来理解
- 浅显理解 Python 闭包
- 理解Python中的闭包
- 关于Python中闭包与装饰器的理解
- python闭包的理解说明
- Python 闭包的理解
- 深入理解python中闭包,闭包的实质
- 理解Python闭包概念
- python中对 函数 闭包 的理解