Day 17
今日内容概要
- 闭包函数简介
- 闭包函数的实际应用
- 装饰器简介
- 装饰器推导流程(重要)
- 装饰器固定模板(通用)
- 装饰器语法糖
今日内容详细
1.闭包函数简介
闭包函数:
1.定义在函数内部的函数(函数嵌套)
2.内部函数使用了外部函数名称空间(局部空间)中的名字
#只有符合这两个条件的函数才叫闭包函数
#如何从全局名称空间调用局部名称空间index函数
def func(name):#定义一个形参 当下面调用时给了一个实参后 相当于name=jason 该关系会放入局部空间中
# name='jason'#当形参绑定实参后就会出现这个关系 该关系放入局部空间中
def index():
print(name)
return index
res=func('jason')#return需赋值才可以调用 所以等于一个res
res()#jason 调用res()就可以使用func函数内的信息 最后return返回的是jason
2.闭包函数的实际应用
1.给函数体代码自定义传参的方式1:通过形参
def func(xxx):
print(xxx)
func('数据值')
2.给函数体代码自定义传参的方式2:闭包函数
def index(name):
# name='jason'
def func():
print(name)
return func
res = index('数据值1')
res()#数据值1
res = index('数据值2')
res()#数据值2
3.装饰器简介
1.装饰器的作用:
在不改变被装饰对象在不改变原来的'调用方式'和'内部代码'的情况下给被装饰对象添加新的功能
eg: #让以下函数每次在执行前都要校验用户身份且不改变原函数的调用方式和内部代码
def func():
print()
func()
2.装饰器的原则:
不允许修改 只可以扩展
储备知识:
1)time.time()
import time #导入一个时间模块
print(time.time())#1657019452 时间戳(秒):当前距离1970年1月1日0时0分0秒所经历的秒数
实际应用:可以统计代码的运行时间
eg:
import time
start_time=time.time()#创建一个代码运行开始时间
for i in range(1000):
print(i)
end_time=time.time()#创建一个代码运行结束时间
print('for循环的执行时间为:%s秒'%(end_time-start_time))#用结束时间-开始时间就是该代码运行了的时间
2)time.sleep(3)
#让程序原地等待3秒再执行
import time#导入一个时间模块
time.sleep(3)#让程序等待3秒再执行
print('zzz')#3秒后打印zzz
4.装饰器推导流程(重要)一步一步优化的步骤
利用装饰器来计算函数执行时间:
'第一次尝试:在调用函数前后加上时间戳'
import time #导入一个时间模块
def index(): #创建一个函数
time.sleep(3) #定义让程序等待3秒再执行
print('zzz') #让函数打印zzz
start_time = time.time() #在调用函数前获取一个开始时间
index() #调用函数index()
end_time = time.time() #在调用函数后获取一个结束时间
print(end_time-start_time)#让结束时间-开始时间就是函数执行时间
'''
缺陷:如果有多个index()需要统计时间,则需要重复编写时间戳代码
解决措施:封装成函数
'''
————————————————————————————————————————————————————————
'第二次尝试:封装函数'
import time #导入一个时间模块
def index(): #创建一个函数
time.sleep(3) #定义让程序等待3秒再执行
print('zzz') #让函数打印zzz
def get_time():#把以下代码封装成函数
start_time = time.time() #在调用函数前获取一个开始时间
index() #调用函数index()
end_time = time.time() #在调用函数后获取一个结束时间
print(end_time-start_time)#让结束时间-开始时间就是程序执行时间
get_time()#调用get_time()函数,结果时打印了zzz和用时时间
'''
缺陷:如果有多个不同的函数需要统计时间,上述方法则不够方便
解决措施:给函数添加形参(动态传参),好让我传什么就用什么赋值
'''
————————————————————————————————————————————————————————
'第三次尝试:变成形参形式,用户输入什么就用什么来调用函数'
import time #导入一个时间模块
def index(): #创建一个函数
time.sleep(3) #定义让程序等待3秒再执行
print('index') #让函数打印'index'
def home():
time.sleep(2)
print('home')
def get_time(xxx):#把以下代码封装成函数(形参是获取一个变量名,当下面调用的实参是函数时,这里也是函数)
start_time = time.time() #在调用函数前获取一个开始时间
xxx() #调用函数(调用的时候实参是哪个函数名就调用哪个函数名的函数)
end_time = time.time() #在调用函数后获取一个结束时间
print(end_time-start_time)#让结束时间-开始时间就是程序执行时间
get_time(index)#调用get_time(index)函数(括号里传的是函数名),结果是打印了'index'和用时时间
get_time(home)#调用get_time()函数(括号里传的是函数名),结果是打印了'home'和用时时间
'''
缺陷1:调用方式改变了,不符合装饰器的定义
解决方式:装饰器推导流程
缺陷2:当需要调用的函数有实参时会报错,因为不同形参个数的函数不兼容
eg:
def func1(a)
pass
get_time(func1)#会报错
解决方式:*args **kwargs 但是在我们目前代码中无法实现
'''
————————————————————————————————————————————————————————
'第四次尝试:装饰器推导流程'#针对有参无参函数如何兼容
import time #导入一个时间模块
def index(name): #创建一个函数并要求有一个参数
time.sleep(1) #定义让程序等待1秒再执行
print('index') #让函数打印'index'
return 'index的返回值'
def home(): #创建一个函数
time.sleep(3) #定义让程序等待3秒再执行
print('home') #让函数打印'home'
return 'home的返回值'
def outer(xxx):#形参是获取一个变量名,当下面调用的实参是函数时,这里也是函数)
def get_time(*args,**kwargs):#*与**在形参中的使用方式 把多余的位置参数赋值给args 也就是args='index'
start_time = time.time() #在调用函数前获取一个开始时间
res=xxx(*args,**kwargs) #调用函数(调用的时候实参是哪个函数名就调用哪个函数名的函数)func(*('index')) 让res接收要调用函数的返回值
end_time = time.time() #在调用函数后获取一个结束时间
print(end_time-start_time)#让结束时间-开始时间就是程序执行时间
return res#返回值
return get_time#返回一个get_time函数名 并给下面的index接收
index = outer(index)#outer(index)把实参(函数名)传给outer的形参里 index接收的是上面的返回值
xxx = index(1)#调用函数()当括号里需要有参数时,就带参数
print(xxx)#打印的是xxx变量名函数的返回值
5.装饰器固定模板(通用)
from functools import wraps
def outer(func_name):
@wraps(func_name) #仅是为了让装饰器不容易被发现 做到真正以假乱真 help(函数名)查看不到真实面目
def inner(*args,**kwargs):
print('执行被装饰对象之前可以做的额外操作')
res = func_name(*args,**kwargs)
print('执行被装饰对象之后可以做的额外操作')
return res
return inner
调用时:
import time#导入一个时间模块
@outer#放入一个装饰器语法糖 等于下面的home = outer(home)
def home():#创建一个函数
time.sleep(1)#让代码等待1秒再执行
print('home')#函数体内部代码
return 'home的返回值'#返回值
#home = outer(home)#home接收的是上面的返回值 outer(home)把实参(函数名)传给outer的形参里
res = home()#用来接收home函数体返回值的变量名
print(res)#实际打印的就是home函数体里的返回值
6.装饰器语法糖
import time#导入一个时间模块
@outer#放入一个装饰器语法糖 等于下面的home = outer(home)
def home():#创建一个函数
time.sleep(1)#让代码等待1秒再执行
print('home')#函数体内部代码
return 'home的返回值'#返回值
# home = outer(home)#home接收的是上面的返回值 outer(home)把实参(函数名)传给outer的形参里
res = home()#用来接收home函数体返回值的变量名
print(res)#实际打印的就是home函数体里的返回值
打印出来的结果与上图一致
作业:
1.编写一个用户认证装饰器
基本要求
执行每个函数的时候必须先校验身份 eg: jason 123
拔高练习(有点难度)
执行被装饰的函数 只要有一次认证成功 那么后续的校验都通过
函数:register login transfer withdraw
提示:全局变量 记录当前用户是否认证
原创文章,作者:Carrie001128,如若转载,请注明出处:https://blog.ytso.com/271980.html