Python中闭包的理解
来源:互联网 发布:大数据营销案例沃尔玛 编辑:程序博客网 时间:2024/06/05 12:04
Python中闭包的理解:
Num01–>定义:
官方定义: 闭包是词法闭包(Lexical Closure)的简称,是引用了自由变量的函数,这个被引用的自由变量将和这个函数一同存在,即使已经离开了创造它的环境也不例外。
自已的理解为: 如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)。
举一个简单的例子来说明:
def addx(x): def addy(y): return x + y return addyxy = 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 = 5def line_func(): b = 55 def line(x): return 2 * x + b return linemy_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 barf=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 barf=foo()print(f())#第二种解决办法:不是太好,不建议,自由变量为可变对象def foo(): a = [1] def bar(): a[0] = a[0] + 1 return a[0] return barf=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的slice
- python编码的理解
- python元组传参的理解
- python 中 *\的理解
- python metaclass的理解
- 理解python的generator
- python transpose的理解
- 理解Python的PoolExecutor
- Python引用的理解
- Python中协程的理解
- python decorator的理解
- python的 __init__ 理解
- Python 字典的理解
- Dynamics 365 SiteMap Designer
- 高德地图java.lang.UnsatisfiedLinkError: dlopen failed:has text relocations
- MySQL数据库(11)
- Laravel 请求
- 实验五项目三
- Python中闭包的理解
- qmp简介 QEMU Machine Protocol
- 台湾李宏毅教授深度学习
- linux c 命令行解析
- Android开发经验(不积跬步无以至千里)
- The specified child already has a parent. You must call removeView() on the child's parent first.错误
- 【DP】洛谷 P1006 传纸条
- (二)caffe 网络训练执行流程
- JAVA设计模式之工厂模式(简单工厂模式+工厂方法模式)