装饰器
闭包函数
-
1.在函数内部在定义一个函数
2.内部函数可以使用外部函数局部名称空间的名字
符合这两条的就被称为闭包函数
def func(name): # 1定义函数func # 3调用时name接收实参
username = name # 4将name的数据值赋值给username
def info(): # 5定义函数info
print(username) # 8打印username的数据值
# 9run:barry
return info # 6函数名info为返回值
res = func('barry') # 2调用函数func,将返回值赋值给res
res() # 7定义返回值info函数
装饰器简介
- 什么是装饰器
在不改变装饰对象原来的'调用'与'函数体代码'的条件下修改装饰对象功能的函数,叫装饰器
- 扩展知识
import time # 调用time模块
print(time.time()) # 时间戳:运行时距离1970年1月1日0时0分0秒所经历的秒数
# run:1657004281.4972255
start_time = time.time() # 将运行时间戳的时间赋值给start_time变量名
time.sleep(1) # 让程序等待一秒
end_time = time.time() # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time) # 求差可得运行第一个时间戳到第二个时间戳的时间
# run:1.0154657363891602(差不多是一秒)
装饰器推导
-
统计函数的执行时间
缺陷:需要反复编写待码
import time # 调用time模块
def func(): # 定义函数func
time.sleep(1) # 让程序等待一秒
print('from func') # 函数的执行结束
# run:from func
start_time = time.time() # 将运行时间戳的时间赋值给start_time变量名
func() # 调用函数func
end_time = time.time() # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time) # 求差可得运行第一个时间戳到第二个时间戳的时间
# run:1.0155069828033447 # 函数funcd的执行时间
-
将统计函数代码改为函数体代码
缺陷:形参数不同的函数无法使用
import time # 调用time模块
def func(): # 定义函数func
time.sleep(1) # 让程序等待一秒
print('from func') # 函数的执行结束
# run:from func
def get_time(a): # 定义函数且用形参接收要调用的函数名
start_time = time.time() # 将运行时间戳的时间赋值给start_time变量名
a() # 调用所需要的函数
end_time = time.time() # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time) # 求差可得运行第一个时间戳到第二个时间戳的时间
# run:1.0118203163146973 # 函数func的执行时间
get_time(func) # 调用get_time函数并将func函数名传给形参
- 使用*和**可以支持形参数不同的函数
import time # 调用time模块
def outer(x): # 定义函数且用形参接收要调用的函数名
def get_time(*a, **b): # 定义函数且用形参接收实参数据值
start_time = time.time() # 将运行时间戳的时间赋值给start_time变量名
x(*a, **b) # 调用所需要的函数,传输实参
end_time = time.time() # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time) # 求差可得运行第一个时间戳到第二个时间戳的时间
return get_time # 函数名get_time为返回值
def func(): # 定义函数func
time.sleep(1) # 让程序等待一秒
print('from func') # 函数的执行结束
# run:from func
func = outer(func) # 调用函数outer,将返回值赋值给func
func() # 定义返回值get_time函数
print(func) # <function outer.<locals>.get_time at 0x000001BB681B70D0>
装饰器各种版本
import time # 调用time模块
def outer(x): # 定义函数且用形参接收要调用的函数名
def get_time(*a, **b): # 定义函数且用形参接收实参数据值
start_time = time.time() # 将运行时间戳的时间赋值给start_time变量名
x(*a, **b) # 调用所需要的函数,传输实参
end_time = time.time() # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time) # 求差可得运行第一个时间戳到第二个时间戳的时间
return get_time # 函数名get_time为返回值
def func(): # 定义函数func
time.sleep(1) # 让程序等待一秒
print('from func') # 函数的执行结束
# run:from func
def lnof(a, b): # 定义函数lnof
time.sleep(2) # 让程序等待一秒
print(a, b) # 函数的执行结束
# run:1 2
func = outer(func) # 调用函数outer,将返回值赋值给func
func() # 定义返回值get_time函数
print(func) # <function outer.<locals>.get_time at 0x000001BB681B70D0>
lnof = outer(lnof) # 调用函数outer,将返回值赋值给lnof
lnof(1, 2) # 定义返回值get_time函数并将实参传给形参
print(lnof) # <function outer.<locals>.get_time at 0x0000020092E87790>
装饰器固定模板
- 可以直接套用的装饰器固定模板
import time # 调用time模块
def outer(x): # 定义函数且用形参接收要调用的函数名
def get_time(*args, **kwargs): # 定义函数且用形参接收实参数据值
print() # 行被装饰对象前可以进行额外操作
res = x(*args, **kwargs) # 执行被装饰函数
print() # 行被装饰对象后可以进行额外操作
return res # 返回真正的返回值
return get_time # 函数名get_time为返回值
-
装饰器语法糖
语法糖会将下面的函数名传给@后面的函数形参
'@装饰函数名'
import time # 调用time模块
def outer(x): # 定义函数且用形参接收要调用的函数名
def get_time(*a, **b): # 定义函数且用形参接收实参数据值
start_time = time.time() # 将运行时间戳的时间赋值给start_time变量名
res = x(*a, **b) # 调用所需要的函数,传输实参
end_time = time.time() # 将运行时间戳的时间赋值给end_time变量名
print(end_time - start_time) # 求差可得运行第一个时间戳到第二个时间戳的时间
return res
return get_time # 函数名get_time为返回值
@outer # 相当于func = outer(func)
def func(): # 定义函数func
time.sleep(1) # 让程序等待一秒
print('from func') # 函数的执行结束
# run:from func
func() # 定义返回值get_time函数
print(func) # <function outer.<locals>.get_time at 0x000001CE84097700>
- 让装饰器不容易被别人发现
from functools import wraps
import time # 调用time模块
def outer(x): # 定义函数且用形参接收要调用的函数名
def get_time(*args, **kwargs): # 定义函数且用形参接收实参数据值
print() # 行被装饰对象前可以进行额外操作
res = x(*args, **kwargs) # 执行被装饰函数
print() # 行被装饰对象后可以进行额外操作
return res # 返回真正的返回值
return get_time # 函数名get_time为返回值
@outer
def func(): # 定义函数func
time.sleep(1) # 让程序等待一秒
print('from func') # 函数的执行结束
info = func
print(info)
作业
- 执行每个函数的时候必须先校验身份
def name(a): # 定义name函数
def get_time(*b, **c): # 定义函数且用形参接收实参数据值
while True:
username = input('输入用户名>>>:').strip() # 输入用户名
password = input('输入密码>>>:').strip() # 输入密码
if username == 'jason' and password == '123': # 判断用户名密码是否正确
a(*b, **c) # 调用所需要的函数,传输实参
print('功能尚未开发完成\n敬请期待')
else:
print('用户名或密码错误')
continue # 用户名或密码错误重新输入
return get_time # 返回get_time 函数名
@name # func = name(func)
def func():
print('登录成功') # 登录成功时运行
func() # 定义返回值get_time函数
- 提高难度
def register():
print('注册功能')
@login_auth
def login():
print('登录功能')
@login_auth
def transfer():
print('转账功能')
@login_auth
def withdraw():
print('提现功能')
register()
login()
transfer()
withdraw()
is_login = {'is_login': False, }
# 2.编写装饰器
def login_auth(func_name):
def inner(*args, **kwargs):
# 2.3判断全局字典is_login对应的值是否是True
if is_login.get('is_login'):
# 2.4直接执行被装饰函数即可
res = func_name(*args, **kwargs)
return res
# 2.1假设是第一次调用 肯定需要校验用户身份
username = input('username>>>:').strip()
password = input('password>>>:').strip()
if username == 'jason' and password == '123':
res = func_name(*args, **kwargs)
# 2.2保存用户登录的状态
is_login['is_login'] = True
return res
else:
print('权限不够 无法执行')
return inner