装饰器
1.装饰器说明
当需要在多段不同程序中执行相同的操作,就需要装饰器
2.装饰器的使用方法
需要将要装饰的函数作为函数传递,装饰器里嵌套函数,返回值是嵌套的函数对象
例:
def desc(fun):
def add_info():
print("开学不快乐")
fun() # login()
print("欢迎来到西安没电大学")
return add_inf
3.装饰器的两种调用方式:
完整代码:
def login():
print("中秋节快乐")
login()
方法一:语法糖
@desc (语法糖) 实际上是login = desc(login)
方法一:调用函数,返回值是函数
login = desc(login)
返回结果:
开学不快乐
中秋节快乐
欢迎来到西安没电大学
4.带有多个装饰器的函数
当使用装饰器时,调用的顺序与装饰器的先后位置有关,在上方的装饰器后调用,在下方的装饰器先调用,而装饰器里嵌套的函数如装饰器一里的wrapper1和装饰器二里的wrapper2,执行时,先执行wrapper1,再执行wrapper2
例:
def print_i(fun):
print("我是第一个装饰器")
def wrapper1(*args, **kwargs):
print("我是第二个装饰器里的嵌套函数")
return fun(*args, **kwargs) # wrapper
return wrapper1
def print_j(fun): # fun=login
print("我是第二个装饰器")
def wrapper(*args, **kwargs):
print("我是第二个装饰器里的嵌套函数")
return fun(*args, **kwargs)
return wrapper
@print_i 调用了第一个装饰器
@print_j 调用了第二个装饰器
def login():
return "看上面,别看我"
print(login())
我是第二个装饰器 >>先调用了位置在后面的装饰器
我是第一个装饰器 >>再调用了位置在前面的装饰器
我是第一个装饰器里的嵌套函数 >>先执行位置在前的装饰器里的嵌套函数
我是第二个装饰器里的嵌套函数 >>后执行位置在后的装饰器里的嵌套函数
看上面,别看我
5.使用装饰器时函数属性发生变化的情况及解决方案
当使用装饰器时,因为将函数传给了装饰器里的嵌套函数,所以函数的属性会随之而变,变为装饰器内嵌套函数的属性
例:
import time
def timeit(fun):
def wrapper(*args, **kwargs):
start_time = time.time()
res = fun(*args, **kwargs)
end_time = time.time()
print("运行时间为:%.6f" % (end_time - start_time))
return res
return wrapper
@timeit
def fun():
print("hello")
print(fun.__name__)
print(fun.__doc__)
wrapper
这是一个wrpper函数
由上可见,当调用装饰器后,函数的函数名和帮助文档也会随着改变,为了让函数保留其性质,可以调functools函数
import time
import functools
def timeit(fun):
@functools.wraps(fun) >>声明将fun函数的性质还给fun
def wrapper(*args, **kwargs):
start_time = time.time()
res = fun(*args, **kwargs)
end_time = time.time()
print("运行时间为:%.6f" % (end_time - start_time))
return res
return wrapper
@timeit
def fun():
print("hello")
print(fun.__name__)
print(fun.__doc__)
fun
None
6.当装饰器中含有参数时:
import functools
import time
def log(kind): # kind="debug"
def add_log(fun):
@functools.wraps(fun)
def wrapper(*args, **kwargs):
# run_time = time.ctime()
# fun_name = fun.__name__
start_time = time.time()
res = fun(*args, **kwargs)
end_time = time.time()
print("<%s> [%s] 函数名: %s, 运行时间:%.5f, 运行返回值结果:%d"
%(kind, time.ctime(), fun.__name__, end_time-start_time, res )
)
return res
return wrapper
return add_log
@log("debug")
# log("debug")==> 返回值是add_log
# add=add_log(add)
def add(x,y):
time.sleep(0.1)
return x+y
print(add(1,2))
<debug> [Wed Aug 22 14:26:36 2018] 函数名: add, 运行时间:0.10018, 运行返回值结果:3
3
7.装饰器的应用
例:装饰器实现计时器,检测列表生成式和map的效率高低
import random
import string
import time
li = [ random.choice(string.ascii_letters) for i in range(100)]
def timeit(fun): # fun_list
def wrapper(*args, **kwargs):
start_time = time.time()
fun(*args, **kwargs)
end_time = time.time()
print("运行时间为:%.6f" % (end_time - start_time))
return wrapper
@timeit
def fun_list(n):
print([2*i for i in range(n)])
@timeit
def fun_map(n):
print(list(map(lambda x:x*2, range(n))))
fun_list(5)
fun_map(5)
[0, 2, 4, 6, 8]
运行时间为:0.000021
[0, 2, 4, 6, 8]
运行时间为:0.000007