闭包
def func():
a=100
def inner_func():
b=99
print(a,b)
return a
# print(a)
# inner_func()
x=func()#100 并没有调用到inner_func()
print(x)
#闭包
#在函数中提出得概念
def func2():
a=100
def inner_func():
b=99
print(a,b)
return inner_func #注意不要加上括号
# print(a)
# inner_func()
x=func2()#100 并没有调用到inner_func()
print(x)#<function func2.<locals>.inner_func at 0x000001E579519048>
x()#100 99
#x就是内部函数,加上()就可以调用这个函数
'''
闭包的条件:
1.外部函数中定义了内部函数
2.外部函数是有返回值的
3.返回的值是:内部函数名
4.内部函数引用了外部函数的变量
格式:
def 外部函数():
...
def 内部函数():
...
return 内部函数
'''
例子
#例子
def func(a,b):
c=10
def inner_func():
s=a+b+c
print('相加之后的结果是:',s)
return inner_func
#调用func
ifunc=func(6,9)
ifunc1=func(2,8)
#调用反出来的内部函数
ifunc1()
ifunc()
'''
相加之后的结果是: 20
相加之后的结果是: 25
'''
同级闭包
#同级闭包
'''
闭包有什么缺点?
1.作用域没有那么直观
2.因为变量不会呗垃圾回收所以有一定的内存占用问题
作用:
1.可以使用同级的作用域!!
2.读取其他元素的内部变量
3.延长作用域
总结:
1.闭包优化了变量,原来需要类对象完成的工作,闭包也可以完成
2.由于闭包引用了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存
3.闭包的好处,使代码变得更简洁,便于阅读代码
4.闭包是理解装饰器得基础
'''
def func():
a=100
def inner_func1():
b=90
s=a+b
print(s)
def inner_func2():
inner_func1()
print('---inner_func2')
return inner_func2
x=func()
x()
'''
190
---inner_func2
'''
装饰器引入
#闭包回顾(返回函数的地址出来)
def func(number):
a=100
def inner_func():
nonlocal a
nonlocal number
number+=1
for i in range(number):#对a进行number+1次加1
a+=1
print('修改后的a:',a)
return inner_func
#调用func
f=func(5)
f()#修改后的a: 106
#地址引用变量和函数
a=10
b=a
print(a)#10
print(b)#10
def test():
print('test-----')
t=test
#调用
t()#test-----
test()#test-----
#函数地址作为参数(装饰器)
def func1(f):
print(f)
f()#调用参数中的函数
print('--->func')
func1(test)#注意test参数不要带括号
'''
<function test at 0x000001886707A048>
test-----
--->func
'''
装饰器使用
def house():
print('我是毛胚房')
def house1():
house()
print('刷漆')
print('铺地板')
#调用函数
house1()
'''
我是毛胚房
刷漆
铺地板
'''
'''
装饰器特点:
1.函数A是作为参数出现的(函数B接收函数A作为参数)
2.要有闭包的特点(外部函数调用外部函数的变量&外部函数返回内部函数的地址)
'''
#定义一个装饰器
def decoratea(func):
a=100
def wrapper():
func()
print('----->刷漆')
print('---->铺地板',a)
print('---->装门')
return wrapper
#使用装饰器
@decoratea#表示把下面的函数作为参数传给这个装饰器
def house():
print('我是毛胚房')
#调用函数house
print(house)
house()#本质是调用wrapper,wrapper里面调用真实house
'''
<function decoratea.<locals>.wrapper at 0x000001CEB9969158>
我是毛胚房
----->刷漆
---->铺地板 100
---->装门
'''
'''
@装饰器类名底层调用步骤:
1.house作为被装饰函数
2.将被装饰函数作为参数传给装饰器decoratea
3.执行decoratea函数
3.1 a=100
3.2 加载函数wrapper进入内存,但是没有调用
4.将返回值赋值给被装饰函数house,因此当我们调用house时其实是调用wrapper函数,
而wrapper函数里面调用了函数参数func才是我们真正的house函数
'''
无参例子
#例子
import time
def decorator2(func):
def wrapper():
print('正在校验中...')
time.sleep(2)
print('检验完成..')
#调用原函数
func()
return wrapper
@decorator2
def f1():
print('----f1--')
'''
正在校验中...
检验完成..
----f1--
'''
'''
@decorator2底层:
1.把f1当作被装饰函数
2.调用decorator2
3.把返回值赋值给f1
'''
f1()
#调用返回值wrapper函数,wrapper函数里面调用f1
有参例子
#例子
import time
def decorator2(func):
def wrapper(x):
print('正在校验中...')
time.sleep(2)
print('检验完成..')
#调用原函数,原函数有参数,这里也要有
func(x)
return wrapper
@decorator2
def f1(n):
print('----f1--',n)
'''
正在校验中...
检验完成..
----f1-- 5
'''
f1(5)#本质是调用wrapper,因此wrapper也要有参数
#调用返回值wrapper函数,wrapper函数里面调用f1
@decorator2
def f3(students):
for stu in students:
print(stu)
students=['lily','tom','lucy']
f3(students)
'''
正在校验中...
检验完成..
lily
tom
lucy
'''
可变参数例子
#如果现在某个被装饰类传入两个参数?
#----》修改装饰类的参数为可变参数
#例子
import time
def decorator2(func):
def wrapper(*x): #*x是5,x是(5,)
print('正在校验中...')
time.sleep(2)
print('检验完成..')
#调用原函数,原函数有参数,这里也要有
func(*x) #对元组拆包,*x是5,将5作为参数
return wrapper
@decorator2
def f1(n):
print('----f1--',n)
'''
正在校验中...
检验完成..
----f1-- 5
'''
f1(5)#本质是调用wrapper,因此wrapper也要有参数
#调用返回值wrapper函数,wrapper函数里面调用f1
@decorator2
def f2(name,age):
print('----f2---',name,age)
f2('lily',20)
'''
正在校验中...
检验完成..
----f1-- 5
正在校验中...
检验完成..
----f2--- lily 20
'''
带关键字参数的装饰器
# 带关键字参数的装饰器
import time
def decorate(func):
def wrapper(*args,**kwargs):
print('正在校验...')
time.sleep(2)
print('校验完毕...')
#调用原函数
func(*args,**kwargs)
return wrapper
@decorate
def f3(students, clazz='1905'):
print('{}班级的学生如下:'.format(clazz))
for stu in students:
print(stu)
students = ['lily', 'tom', 'lucy']
f3(students, clazz='1904')
'''
正在校验...
校验完毕...
1904班级的学生如下:
lily
tom
lucy
'''
双层装饰器
#双层装饰器
def zhuang1(func):
print('--->1 start')
def wrapper1(*args,**kwargs):
func()
print('刷漆')
print('--->1 end')
return wrapper1
def zhuang2(func):
print('--->2 start')
def wrapper2(*args,**kwargs):
func()
print('铺地板,装门..')
print('---->2 end')
return wrapper2
@zhuang2
@zhuang1
def house():
print('我是毛胚房...')
#调用
house()
'''
1.@zhuang1底层
2.@zhuang2底层
3.调用house,看当前house本质是谁
双层装饰器的调用是符合就近原则,先调用zhuang1,把house作为zhuang1的参数,zhuang1返回wrapper1给house,此时house=wrapper1
然后zhuang2就把house(此时是wrapper1)作为参数,返回wrapper2给house,此时house=wrapper2
接着调用了house,实际是调用wrapper2,里面的func是wrapper1,wrapper里面的func是原始的house
'''
'''
--->1 start
--->1 end
--->2 start
---->2 end
我是毛胚房...
刷漆
铺地板,装门..
'''
装饰器带参数
#装饰器带参数(必须用三层函数才可以使得装饰器带参数)
'''
带参数的装饰器是三层的
最外层的函数负责接收装饰器参数
里面的内容还是原装饰器的内容
'''
def outer(a):#在原来两层基础上多加一层用来接收参数
def decorate(func):
def wrapper(*args,**kwargs):
func(*args)
print('---->铺地砖{}块'.format(a))
return wrapper
return decorate
@outer(10)
def house(time):
print('我{}日期拿到的房子的钥匙,是毛胚房..'.format(time))
house('2021-05-08')
'''
我2021-05-08日期拿到的房子的钥匙,是毛胚房..
---->铺地砖10块
'''
@outer(100)
def street():
print('新修街道名字是:黑泉路')
street()
'''
新修街道名字是:黑泉路
---->铺地砖100块
'''
装饰器的应用
#装饰器的应用
#开发:登录验证
import time
#登录状态
islogin=False
def login():
global islogin
username=input('请输入用户名')
password=input('请输入密码')
if username=='admin' and password=='123456':
islogin=True
#定义一个装饰器,进行付款验证
def login_required(func):
def wrapper(*args,**kwargs):
print('---付款----')
#验证用户有没有登录
if islogin:
func(*args,**kwargs)
else:
#跳转到登录页面
print('请先进行登录')
login()
return wrapper
@login_required
def pay(money):
print('正在付款,付款金额是{}元'.format(money))
print('付款中...')
time.sleep(1)
print('付款完成')
#调用
pay(100)
pay(200)
'''
---付款----
请先进行登录
请输入用户名admin
请输入密码123456
---付款----
正在付款,付款金额是200元
付款中...
付款完成
'''