1、闭包的定义
闭包是嵌套在函数中的函数。
闭包必须是内层函数对外层函数的变量(非全局变量)的引用。
2、理解闭包
被引用的非全局变量也称作自由变量,这个自由变量会与内层函数产生一个绑定关系。
自由变量不会再内存中消失。
外部函数返回了内部函数
通俗点说:
闭包是一个函数,这个函数是嵌套在另外一个函数里边,且这个函数引用了外层函数的变量(非全局变量)
3、 闭包书写步骤
定义外部函数
定义外部函数,在内部函数中使用外部函数的变量
外部函数返回内部函数的地址(内部函数名就饿内部函数的地址)
# 定义内部函数:
def outer(num):
# 2.定义内部函数,在内部函数中使用外部函数的变量
def inner(num1):
print(num + num1)
# 3.外部函数返回内部函数的地址
return inner # 函数名字就是函数地址
if __name__ == '__main__':
# 创建闭包实例
func = outer(100) # 此时func相当于是inner
# 调用闭包
func(10) # 此时调用inner函数,保存的num值为100
# 可以创建多个闭包实例,不同的闭包实例之间,不会相互影响
4、闭包的使用
需求:
根据配置信息使用闭包实现不同人的对话信息,例如对话:
张三:到北京了吗?
李四:已经到了,放心吧。
实现步骤说明:
定义外部函数接受不同的配置信息参数,参数是人名
定义内部函数接受对话信息参数
在内部函数里面把配置信息和对话信息进行拼接输出
def outer(name):
# 定义内部函数,参数是 说话的信息
print(f'{name}:到北京了吗?')
def inner(name1):
# 内部函数中,将name和info进行拼接输出
print(f'{name1}:已经到了,放心吧。')
# 外部函数返回内部函数的地址
return inner
# 创建闭包实例
if __name__ == '__main__':
func = outer('张三')
func('李四')
注意点:由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。
5、闭包修改外部函数变量(理解)
函数内部想要修改全局变量,使用global关键字
在闭包函数内部,想要修改外部函数的局部变量,需要使用nonlocal关键字
def outer():
num = 10
def inner():
# num = 100 # 不是修改外部变量的值,重新定义的局部变量
nonlocal num # 声明使用外部变量 num 不重新定义
num = 100
print(f'调用inner之前:{num}')
inner()
print(f'调用inner之后:{num}')
return inner
func = outer()
func()
6、闭包的作用
保存局部信息不被销毁,保证数据的安全性
7、如何判断一个嵌套函数是不是闭包
1,闭包只能存在嵌套函数中
2, 内层函数对外层函数非全局变量的引用(使用),就会形成闭包。
案例1 :
def wrapper():
a = 1
def inner():
print(a)
return inner
ret = wrapper()
#例一是闭包
案例2:
# 例二:
a = 2
def wrapper():
def inner():
print(a)
return inner
ret = wrapper()
#例二不是闭包
案例3:
# 例三:
def wrapper(a,b):
def inner():
print(a)
print(b)
return inner
a = 2
b = 3
ret = wrapper(a,b)
#也是闭包
8、如何用代码判断闭包?
查看这个函数有没有自由变量就行了
# 函数名.__code__.co_freevars 查看函数的自由变量
print(avg.__code__.co_freevars) # ('series',)
# 函数名.__code__.co_varnames 查看函数的局部变量
print(avg.__code__.co_varnames) # ('new_value', 'total')
# 函数名.__closure__ 获取具体的自由变量对象,也就是cell对象。
# (<cell at 0x0000020070CB7618: int object at 0x000000005CA08090>,)
# cell_contents 自由变量具体的值
print(avg.__closure__[0].cell_contents) # []
上面案例三最难判断是不是闭包,为了进一步确认,用代码判断闭包
# 例三:
def wrapper(a,b):
def inner():
print(a)
print(b)
return inner
a = 2
b = 3
ret = wrapper(a,b)
#如何用代码判断闭包?
print(ret.__code__.co_freevars)
('a', 'b')
Process finished with exit code 0