# **************************************************************************
# Python学习
# **************************************************************************
# ** 所属主题: 函数
# ** 所属分层: 32 装饰器
# ** 功能描述: 32 装饰器
# ** 创 建 者: 陈红伟
# ** 创建日期: 2021/3/27 10:44 下午
# **************************************************************************
# ** 修改日期 修改人 修改内容
# ** 2021/3/28 陈红伟 新增学习内容代码
# **************************************************************************
# 装饰器:
"""
1、什么是装饰器:
器指的是工具,可以定义成函数
装饰指的是为其他事物添加额外的东西点缀
合到一起的解释:
装饰器指的是定义一个函数,该函数是用来为其他函数的添加额外的功能(闭包函数)
2、为什么要用装饰器:
开放封闭原则
开放:指的是对拓展功能是开放的
封闭:指的是对修改源代码是封闭的
装饰器就是在不修改被装饰器对象源代码以及调用方式的前提下为被装饰对象添加新功能
3、怎样使用装饰器:
"""
###################################################################
# 无参装饰器 示例:@wrapper
###################################################################
# 需求:在不修改index函数的源代码以及调用方式的前提下为其添加统计运行时间的功能
def index(x,y):
time.sleep(2)
print('index %s %s' %(x,y))
# 解决方案一:虽然效果实现了,但是不符合需求,因为修改了源代码
import time
def index(x,y):
start = time.time()
time.sleep(2)
print('index %s %s' %(x,y))
stop = time.time()
print(stop-start)
index(111,222)
# index 111 222
# 2.0040969848632812
# 解决方案二:
import time
def index(x,y):
time.sleep(2)
print('index %s %s' %(x,y))
def haoshi(x,y):
start = time.time()
index(x,y)
stop = time.time()
return (stop-start)
print(haoshi(111,222))
# index 111 222
# 2.0044641494750977
# 解决方案三:利用装饰器解决
import time
def index(x,y):
time.sleep(2)
print('index %s %s' %(x,y))
# 装饰器
def wrapper(func):
def haoshi(*args,**kwargs):
start = time.time()
func(*args,**kwargs)
stop = time.time()
return (stop-start)
return haoshi
# 偷梁换柱
f = wrapper(index) # 还可以使用一种方式实现同样的逻辑: 在被装饰对象(函数)的正上方写上 "@+装饰器名字",但是装饰器名字要先定义好,再使用; 例如:在index()函数上面写上@wrapper
print(f(111,222))
# index 111 222
# 2.000530958175659
# 语法糖 在被装饰对象(函数)的正上方写上 "@+装饰器名字",但是装饰器名字要先定义好,再使用; 例如:在index()函数上面写上@wrapper
@wrapper
def index(x,y):
time.sleep(2)
print('index %s %s' %(x,y))
print(index(3333,3333))
# index 3333 3333
# 2.0049400329589844
# 总结:
def outer(func):
def wrapper(*args,**kwargs):
# 1、调用原函数
# 2、为其增加新功能
print('wrapper ....')
res = func(*args,**kwargs)
return res
return wrapper
@outer # 等价于 func_add = outer(func_add)
def func_add(a,b):
return a+b
print(func_add(1,1))
# wrapper ....
# 2
def func_add(a,b):
return a+b
# 去掉装饰器后
print(func_add(1,1)) # 2 只是按源函数执行,并没有用到装饰器装饰(此处指的是没有打印出wrapper ...)
print(func_add) # <function func_add at 0x7fdaa24059d0> 去掉装饰器之后,可以看到func_add的内存地址指向的是func_add
@outer # 等价于 func_add = outer(func_add)
def func_add(a,b):
return a+b
# 但是,还是有个缺点,并不是完全一致
print(func_add) # <function outer.<locals>.wrapper at 0x7ffb75d058b0> 可以看到func_add的内存地址指向的是wrapper
# 如果想变成和原函数的属性信息(name、doc 等等)一样,(实现真正的偷梁换柱),需要引入包。wraps
from functools import wraps
def outer(func):
def wrapper(*args,**kwargs):
# 1、调用原函数
# 2、为其增加新功能
print('wrapper ....')
res = func(*args,**kwargs)
return res
return wrapper
print(func_add.__name__) # wrapper 因为被封装了
def outer(func):
@wraps(func)
def wrapper(*args,**kwargs):
# 1、调用原函数
# 2、为其增加新功能
print('wrapper ....')
res = func(*args,**kwargs)
return res
return wrapper
print(func_add.__name__) # wrapper 这里还有疑问??????????????????
###################################################################
# 有参装饰器 示例:@wrapper("hello")
###################################################################
# 一、知识储备
# 由于语法糖@的限制,outter函数只能有一个参数,并且只用来接受被装饰对象的内存地址;
# 所以wrapper参数不能动,outter参数也不能动,那我需要其他的参数怎么办呢?
def outter(func):
def wrapper(*args,**kwargs):
res = func(*args,**kwargs)
return res
return wrapper
@outter
def index(x,y):
print(x,y)
# 需求,我要在原来的func的基础上加上验证的功能:
def youcan_func(check):
def outter(func):
def wrapper(*args, **kwargs):
flag = False
if check == 'file':
flag = True
if check == 'oldp':
flag = True
if check == 'mysql':
flag = True
if flag:
print(args,kwargs)
res = func(*args, **kwargs)
else:
res = None
return res
return wrapper
return outter
def func(x,y):
return x+y
# 语法糖
@youcan_func(check='file') # 相当于 调用了函数youcan_func(check='file') 变成了@outter ;
# 然后@outter就是无参装饰器的语法糖了(相当于using_file=outter(using_file)的内存地址)
# 然后调用using_file 其实就是调用wrapper
def using_file(x,y):
print('using file check')
return x*y
@youcan_func(check='oldp')
def using_oldp(x,y):
print('using oldp check')
@youcan_func(check='mysql')
def using_mysql(x,y):
print('using mysql check')
print(using_file(1,1))
# (1, 1) {}
# using file check
# 1 # 特别注意⚠️: 这里是1 不是2 因为执行的是1*1 不是 1+1
# using_oldp(2,2)
# using_mysql(3,3)
# 总结:
def 原来的函数(x,y):
return x+y
# 无参装饰器模版:
def 无参装饰器(原来的函数):
def wapper(*args,**kwargs):
res = 原来的函数(*args,**kwargs)
return res
return wapper
# 有参装饰器模版:
def 有参装饰器(q,w):
def 无参装饰器(原来的函数):
def wapper(*args,**kwargs):
if(q==1 and w==1):
res = 原来的函数(*args,**kwargs)
else:
pass
return res
return wapper
return 无参装饰器
# 怎么用?
# 在原来的函数上方写上@无参装饰器(q=1,w=1)
# 例如:
@无参装饰器
def 原来的函数1(x,y):
return x+y
# 调用:
print(原来的函数1(1,2))
Python基础32:装饰器--无参、有参装饰器
最新推荐文章于 2022-08-08 17:45:31 发布