闭包 python_Python的闭包

地位:闭包 和函数有关系

解释:python中一切皆对象:

函数可以赋值给变量,例如 a = def func(),

可以把函数当做参数,传入一个函数

可以把函数当做一个函数的返回结果

示例:Python中允许的正确的调用方法:

def curve_pre():

def curve():

print('This is a funcion')

return curve #函数作为返回值

func = curve_pre()

func()

#产生调用,输出 This is a funcion

将上述示例扩展为闭包:注意:

闭包内的变量与闭包外的变量没有关系

示例:

def curve_pre():

a = 25 #a在curve外部

def curve(x):

return a*x*x

return curve #函数curve作为返回值

func = curve_pre()

print(func(2)) #打印100

外部变量对一般函数的影响:

a = 10

def f(i):

return a*i

print(f(2)) #打印20

函数外面的a影响到了函数内a的值

外部变量对闭包的影响:

a = 10

print(func(2)) #打印100

调用外面的a没有影响到函数内a的值,def curve(x)内的a仍然是def curve_pre()内的a的值

上述就是闭包的现象

闭包定义:由函数以及函数定义时外部的变量构成的整体,叫闭包

闭包 = 函数 + 原函数所处环境的变量(原函数外部)

注意:上述函数所处环境的变量不能是全局变量,即:至少需要两个结构体嵌套

闭包内的环境变量:

保存在curve_pre().__closure__内

print(func.__closure__)

#输出:(,)

print(func.__closure__[0].cell_contents)

#输出:25

注意:单一函数 + 不同的外部变量 = 多种不同的闭包(类似设计模式的工厂模式)

闭包的调用方式:正常非闭包函数的调用:

代码:

def func1():

a = 10

def func2():

a = 20

print("func2's a = ",a) # 20 运行顺序:2

print("func1's a = ",a) # 10 运行顺序:1

func2()

print("func1's a = ",a) # 10 运行顺序:3

func1()

注意:

上述是一个函数的调用,不是一个闭包,可以使用__closure__来判断是否为闭包

测试是否是闭包:

def func1():

a = 10

def func2():

a = 20

return a

return func2

func2()

func1()

f = func1()

print(f.__closure__) #输出:None

原因:

func2中的a被当做了局部变量,此时func2函数内并没有产生对外部变量的引用!

所以,并没有构成一个闭包

修改为闭包的方式:

def func1():

a = 10

def func2():

#a = 20 将局部变量a注释

c = a * 20

return func2

func2()

func1()

f = func1()

print(f.__closure__)

#输出:(,)

成为闭包的原因:

将func2中的局部变量a去掉后,只要func2中产生对外部变量a的使用,就可以被作为闭包

闭包一定要引用外部环境的变量

闭包的应用:要求:

对于x,y 按顺序x=3,y=3;x=5,y=8;x=6,y=14

本质:

需要对中间变量进行保存

非闭包实现:(失败)

origin = 0

def walk(step):

new_pos = origin + step #这一步origin是外面的全局变量

origin = new_pos

#此处的赋值会出错,因为如果函数内部有赋值操作,那么origin会变成局部变量,从而导致上一句中找不到origin的定义

return origin

print(walk(3))

print(walk(5))

print(walk(6))

上述代码修改为:(借助global,成功)

origin = 0

def walk(step):

global origin #显式的声明全局变量之后,就不会讲origin作为局部变量

new_pos = origin + step

origin = new_pos

return origin

print(walk(3)) #3

print(walk(5)) #8

print(walk(6)) #14

闭包方式:(失败)

origin = 0

def func1(pos):

#pos成为了环境的变量

def walk(step):

new_pos = pos + step

pos = new_pos

#此处报错UnboundLocalError: local variable 'pos' referenced before assignment

return new_pos

return walk

tour = func1(origin)

print(tour(3)) #3

print(tour(5)) #8

print(tour(6)) #14

修改为:(借助nonlocal,成功)

origin = 0

def func1(pos):

#pos成为了环境的变量

def walk(step):

nonlocal pos #显式声明pos是一个本地变量

new_pos = pos + step

pos = new_pos

#此处报错UnboundLocalError: local variable 'pos' referenced before assignment

return new_pos

return walk

tour = func1(origin)

print(tour(3)) #3

print(tour.__closure__[0].cell_contents) #3

print(tour(5)) #8

print(tour.__closure__[0].cell_contents) #8

print(tour(6)) #14

print(tour.__closure__[0].cell_contents) #14

使用闭包的优点:(函数式编程)

没有使用全局变量origin,所有的变量操作均在闭包内部

闭包+nonlocal关键字可以完成中间变量的记录,打印__closure__[0].cell_contents也会发现,闭包确实记录了中间变量

闭包的扩展:可以实现设计模式中的;工厂模式

闭包内的变量会常驻内存,使用时要注意

闭包不是函数式编程的全部,只是一种体现

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值