分类目录——py基础
装饰器,顾名思义,为函数额外装饰一些功能
通过这么一个例子来解释装饰器存在的意义,假使我写了几个函数来实现同一个需求,我想测试一下这个函数的效率,通过测运行耗时的方法。但是,如果在每个函数中都去写同样的测时间的操作,三五个函数还好说,一旦想测的函数多了,这个工作量就~~~
装饰器就是这样一种机制,只需要在一个函数定义时添加一个标记,就可以给该函数执行前后添加装饰
的内容。
其实用方式如下例所示
import time
def timmer1(f): # 装饰器函数
def inner():
start = time.time() # time.time()获得当前时间
ret = f() # 执行被装饰的函数
end = time.time()
print(end - start)
return ret
return inner # 闭包的写法
# 不用语法糖修饰的方式
# @timmer # 语法糖 @装饰器函数名
def func1(): # 被装饰的函数
time.sleep(0.01) # 暂停0.01s
print('被装饰的函数执行体')
return '返回值'
func1 = timmer1(func1) # 不用语法糖修饰的方式,手动实现装饰
ret1 = func1()
# 被装饰的函数执行体
# 0.011034488677978516
print(ret1)
# 返回值
# 用语法糖修饰——在函数声明前添加 @装饰器函数名 的标记
@timmer1 # 语法糖 @装饰器函数名
def func2(): # 被装饰的函数
time.sleep(0.01)
print('被装饰函数执行体')
return '返回值'
# func = timmer(func)
ret2 = func2() # 使用语法糖的形式,直接通过函数名调用即可
# 被装饰函数执行体
# 0.010964632034301758
print(ret2)
# 返回值
上面的装饰器是没有传参的方式,下例是有传参的装饰器使用方式
def timmer2(f): # 装饰器函数
def inner(*args, **kwargs):
# (1,2) /(1)
start = time.time()
ret = f(*args, **kwargs) # 传入动态参数,该装饰器就能兼容不同参数的函数
end = time.time()
print(end - start)
return ret
return inner
@timmer2 # 语法糖 @装饰器函数名
def func1(a, b): # 被装饰的函数
time.sleep(0.01)
print('a & b', a, b)
return a + b
ret1 = func1(1, b=2) # inner()
# a & b 1 2
# 0.010001659393310547
print('ret1:', ret1)
# ret1: 3
def func2(a): # 被装饰的函数
time.sleep(0.01)
print('this is', a)
return a * a
func2 = timmer2(func2) # 不使用语法糖的方式时,就需要手动把函数封装进装饰器函数
ret2 = func2(3) # inner()
# this is 3
# 0.010001659393310547
print('ret2:', ret2)
# ret2: 9
- 归还被装饰的函数的属性
from functools import wraps
# 在教程那个版本中,当一个函数被装饰装饰了之后,相当于执行了fun = wrapper(fun),
# fun这个函数名(fun.__name__)就不复存在了,就变成了inner
# 在inner定义之前添加@wraps(func)也是调用了一个别人封装的装饰器,为fun函数赋值他原本的函数名,当然不止改名字,还有其他的作用
def wrapper(func): #func = holiday
@wraps(func) # 调用别人封装的装饰器,归还func的一些属性,通过注释与取消注释会发现func.__name__输出不同的结果
def inner(*args,**kwargs):
print('装饰前')
ret = func(*args,**kwargs)
print('装饰后')
return ret
return inner
@wrapper #holiday = wrapper(holiday)
def function(num):
'''function的注释'''
print('function的执行, 传入的值:%d'%num)
return 'function的返回值'
print(function.__name__)
print(function.__doc__) # 函数注释
ret = function(3) #inner
print(ret)
# function
# function的注释
# 装饰前
# function的执行, 传入的值:3
# 装饰后
# function的返回值
- 带参数的装饰器
实现方式,在定义的装饰器之外再封装一个函数,用来传参数
# 带参数的装饰器——在装饰器外层再套一个
# 如果装饰了很多函数,后期可能要取消装饰,设置一个全局参数来控制是否进行装饰,就要对装饰器传参
# 而装饰器已经传了参数func(即函数名),为了再传入参数,在装饰器外层再封装一个函数
import time
FLAGE = True # 只需通过设置这个超参数,即可控制所有被装饰器修饰的函数是否执行装饰器
def timmer_out(flag):
def timmer(func):
def inner(*args,**kwargs):
if flag:
start = time.time()
ret = func(*args,**kwargs)
end = time.time()
print(end-start)
return ret
else:
ret = func(*args, **kwargs)
return ret
return inner
return timmer
# 装饰器实现写法1
# timmer = timmer_out(FLAGE)
# @timmer
# 装饰器实现写法2
@timmer_out(FLAGE) #wahaha = timmer(wahaha)
def wahaha():
time.sleep(0.1)
print('wahahahahahaha')
@timmer_out(FLAGE)
def erguotou():
time.sleep(0.1)
print('erguotoutoutou')
wahaha()
erguotou()
# wahahahahahaha
# 0.10030055046081543
# erguotoutoutou
# 0.10075545310974121
- 多个装饰器装饰同一个函数
# 一个函数被多个装饰器装饰
def wrapper1(func):
def inner():
print('*******************1装饰前')
func()
print('*******************1装饰后')
return inner
def wrapper2(func):
def inner():
print('¥¥¥¥2装饰前')
func()
print('¥¥¥¥2装饰后')
return inner
@wrapper1
@wrapper2
def f():
print('f的执行体')
f()