闭包
闭包的定义
闭包是函数内部定义的函数
1)闭包是嵌套在函数中的函数
2)闭包必须是内层函数对外层函数变量(非全局变量)的引用
构成条件
1)函数中嵌套一个函数;
2)内层嵌套函数,对外部作用域有一个非全局变量的引用:
3)外层函数的返回值是内层函数的函数名
# 闭包模板
def outF():
sum=n # 定义一个非全局变量
def inF(n):
return sum+1
return inF # 外层函数返回值是内层函数的函数名
闭包的作用:
保存局部信息不被销毁,保证数据的安全性
闭包的应用
1)可以保存一些非全局变量但是不易被销毁 改变的数据
2)装饰器
3)实现数据锁定
# 函数的嵌套
def outer():
n=10 # n 为非全局变量
def inner():
n=20 # n为内层函数的局部变量
print('inner函数n = ',n)
print('outer函数n = ',n)
inner()
outer()
# 改为闭包形式
def outer(m):
n=10 # n 为非全局变量
def inner():
print('inner函数n+m = ',n+m)
return inner
ou=outer(2)
print(ou)
print(ou())
# 修改外部函数中的变量
def outer(a):
def inner():
nonlocal a # 给外层函数变量声明
a+=1
print(a)
return inner
ot=outer(1)
ot()
装饰器
本质上就是一个闭包的函数,可以让被装饰的函数在不需要做任何改变的前提下去增加额外的功能。装饰器返回值是一个函数对象。
装饰器的功能:
语法糖:
装饰器的使用方法:
1.先定义一个装饰函数(帽子)(也只可以用类偏函数实现)
2.再定义你的业务函数或者类(人)---这是真正要执行的
3.最后把这顶帽子带在这个人头上去
# 标准版装饰器的模板
def wrapper(func):
def inner(*args,**kwargs):
res=func(*args,**kwargs)
return res # 可有可无
return inner
# 日志打印器
# 装饰器:本质是闭包函数
def logger(func):
def wrapper(*args):
print('准备开始计算:{}函数了'.format(func.__name__))
# 真正执行的业务函数
func(*args)
print('执行完成!')
return wrapper
#第一种方法
def add(x,y): # 求和函数
print('{}+{}={}'.format(x,y,x+y))
# 使用装饰器来装饰函数
# 把函数名add作为参数传入到装饰函数 --- 装饰函数的本质
temp=logger(add) # 调用logger函数
temp(2,3) # 实现wrapper调用
# 日志打印器
# 装饰器:本质是闭包函数
def logger(func):
def wrapper(*args):
print('准备开始计算:{}函数了'.format(func.__name__))
# 真正执行的业务函数
func(*args)
print('执行完成!')
return wrapper
#第二种方法
@logger
def add(x,y): # 求和函数
print('{}+{}={}'.format(x,y,x+y))
add(200,300) # 和普通调用业务函数的调用和传参方式一致
拓展:为什么不直接用函数的封装,给它添加额外功能,而要使用装饰器?
因为装饰器可以实现代码的复用----一个模板,给多个业务函数添加额外的功能。
装饰器- - -参数相关
无参数
# 无参数的函数(被装饰的函数(业务函数)无参数
# 装饰器函数本质:通过业务作为参数传入到装饰器函数里面
def test(fn):
def inner(): # fn 形参代表真正业务函数的函数名
print('这是inner')
fn()
return inner
# 法一:
def t1():
print('这是t1')
t=test(t1) # t1作为参数传入到装饰器函数里面去
t()
# 法二: 使用@
@test
def t2():
print('这是t2')
t2()
有参数
# 被装饰的函数有参数
def demo(fn):
def inner(a,b): # fn 形参代表真正业务函数的函数名
print('这是inner:%s,%s'%(a,b))
fn(a,b) # 真正的业务函数
return inner
@demo
def test(a,b):
print('结果是:',(a+b))
test(1,2)
多层嵌套
# 多层嵌套
def exam(fn):
def funa(x,y):
print('funa函数中的值:%s,%s' %(x,y))
def inner(a,b):
print('inner函数中的值:%s,%s' %(a,b))
fn(a,b)
return inner
return funa
@exam
def test(a,b):
print('结果是:',(a+b))
test(1,2)(3,4)
被装饰的函数有不定长参数
# 被装饰的函数有不定长参数
# 函数参数定义顺序:
# 必选参数 默认参数 可变参数 命名关键字参数和关键字参数
def funa(fn):
def inner(*args,**kwargs):
print(f'开始计算:{fn.__name__}函数了')
fn(*args,**kwargs) # 真正的业务函数
print('执行完成!')
return inner
@funa
def add(*a,**b):
print(a)
print(b)
add(2,3,4,5,6,7,a=1,b=3) # 关键字传参方式 key = value
回调函数
回调函数就是一个参数,将这个函数作为参数传到另一个函数里面,当那个函数执行完之后,再执行传进去的这个函数。这个过程就叫做回调。
回调函数就是回头调用的意思,主函数的任务先调用完,回头再调用该函数
def test(m,n):
if m==2:
n()
else:
print('不可调用')
def one():
print('函数一')
def two():
print('函数二')
test(2,one)