装饰器
装饰器本身就是一个为其他函数添加附加功能的函数
装饰器原则:
- 不修改被修饰函数的源代码
- 不修改被修饰函数的调用方式
比如要增加检测一段代码的执行时间
可以重写源代码
import time
def A():
start = time.time()
res = 0
for i in l
res += i
end = time.time()
print(end-start)
return res
是可以这样写的
但是如果你有n个函数都需要 求运行时间的话
你不可能一个函数一个函数的去改
况且改源代码违反开放封闭原则
可以采用回调的方式
import time
def A():
pass
def B():
pass
def C():
pass
def pack(func):
start = time.time()
func()
end = time.time()
print(end-start)
pack(A)
pack(B)
pack(C)
不过要是用回调的话,调用方式就发生变化了
多数情况下是这样
我要给线上正在运行中的代码添加一些功能
但调用方式是不变的
装饰器
装饰器 实际上就 等于
- 高阶函数
- 函数嵌套
- 闭包
import time
def outer(func):
def inner():
start = time.time()
func()
end = time.time()
print(end-start)
return inner
@outer
def A():
pass
@outer
def B():
pass
@outer
def C():
pass
A()
B()
C()
原来的代码不动,不过每个代码都新增了检测运行时间的功能
高阶函数
高阶函数的定义
- 函数接收的参数是一个函数名
- 函数的返回值是一个函数名
- 满足上述条件任意一个,都可以称之为高阶参数
函数接收一个函数名
def A():
pass
def pack(func):
func()
pack(A) # 相当于直接调用A()
函数接收一个函数名并返回函数名
def A():
pass
def pack(func):
return func
pack(A)() # pack(A) 就相当于A 再加上一个()就是调用A()
# 或者 可以 A = pack(A)
# A()
函数嵌套
在一个函数(私有作用域)中定义另一个函数
在函数中打印locals() 会返回
{'son': <function father.<locals>.son at 0x0000018DC74657B8>, 'name': 'zzz'}
可以看到了 son指向一个函数对象
name指向一个字符串对象
如果不在函数内部调用的话,就算执行外部的函数
里面的函数也不会执行
装饰器基本实现
import time
def outer(func):
def inner():
print('新功能1')
func()
print('新功能2')
return inner
# 用到了闭包 高阶函数 以及 函数的嵌套
def t():
time.sleep(1)
print(123)
t = outer(t)
t()
如果这样写的话,那每给一个函数添加功能,就需要进行一次重新的赋值
这样很复杂
于是乎可以用语法糖@来解决问题
import time
def outer(func):
def inner():
print('新功能1')
func()
print('新功能2')
return inner
# 用到了闭包 高阶函数 以及 函数的嵌套
@outer # 就相当于 t = outer(t)
def t():
time.sleep(1)
print(123)
t()
- 如果被修饰的函数有返回值的话
import time
def outer(func):
def inner():
print('新功能1')
result = func() # 将传进来的被修饰函数的返回值赋值给一个局部变量
print('新功能2')
return result+'d' # 返回处理后的返回值
return inner
# 用到了闭包 高阶函数 以及 函数的嵌套
@outer # 就相当于 t = outer(t)
def t():
time.sleep(1)
print(123)
return 'abc'
print(t()) # 先执行t() 然后打印t()的返回值
- 如果被修饰的函数有形参的话
import time
def outer(func):
def inner(*args,**kwargs):
# 无论被修饰的函数需要多少实参,这里都能接收到(接收到在原封不动的传给函数)
print('新功能1')
result = func(*args,**kwargs)
# 将传进来的被修饰函数的返回值赋值给一个局部变量
# 这里不去掉*的用途的解包
# 把传进来的元组和字典 解成 具体的参数
print('新功能2')
return result+'d' # 返回处理后的返回值
return inner
# 用到了闭包 高阶函数 以及 函数的嵌套
@outer # 就相当于 t = outer(t)
def t(name,age):
time.sleep(1)
print(123)
return 'abc'
print(t()) # 先执行t() 然后打印t()的返回值
装饰器添加验证功能
一个简单的模拟登陆验证功能
def auth_func(func):
def wrapper(*args,**kwargs):
username = input("请输入用户名: ").strip()
password = input("请输入密 码: ").strip()
if username == 'px' and password=="123":
res = func(*args,**kwargs)
return res
else:
print("用户名或密码错误")
return wrapper
@auth_func
def index():
print("欢迎来到主页")
登陆验证模拟session功能
user_list = [
{'name': 'px1', 'passwd': '123'},
{'name': 'px2', 'passwd': '123'},
{'name': 'px3', 'passwd': '123'}
# 假如说这是数据库中用户的信息
]
current_dic = {'username': None, 'login': False} # 用户登录状态
def auth_func(func):
def wrapper(*args, **kwargs):
# 首先判断当前用户的登录状态,已经登录的话可以直接进行访问
if current_dic['username'] and current_dic['login']:
res = func(*args, **kwargs)
return res
username = input("请输入用户名: ").strip()
password = input("请输入密 码: ").strip()
for user_dic in user_list:
if username == user_dic['name'] and password == user_dic['passwd']:
# 如果登录时输入的信息在数据库中,那么就表示登录成功
# 然后改一下 用户登录状态
current_dic['username'] = username
current_dic['login'] = True
res = func(*args, **kwargs)
return res
else:
print("用户名或密码错误")
return wrapper
@auth_func
def index():
print("欢迎来到主页")
index()