我们在做python编程的时候,经常会遇到函数定义的时候,最上面一行有@符号的语句,这叫做装饰器。
装饰器,英文名为Decorators,用一句话来简单说一下就是:在不改变当前函数的逻辑基础上,赋予当前函数更多的能力。
知识点1:函数也是对象,可以作为参数
函数也是对象,也就是我们可以直接使用函数作为参数,传入到另一个函数。
def hi(name='Andy'):
print(f'hello,{name}!')
def printf(fn):
print(fn)
printf(hi)
运行结果:
知识点2:函数中也可以定义函数,同时返回函数
在函数中定义另和函数,另一个函数是可以作为对象直接返回。
def hi(name='Andy'):
print(f'hello,{name}!')
def printf(fn):
def wrapper():
print(fn)
return wrapper
printf(hi)()
运行结果:
知识点3:函数中调用【作为参数的函数】
def hi(name='Andy'):
print(f'hello,{name}!')
def printf(fn):
def wrapper(*args, **kwargs):
print('这里是fn的前置逻辑')
fn(*args, **kwargs)
print('这里是fn的后置逻辑')
return wrapper
printf(hi)(name='ruby')小提示:*args是指python函数的参数没有给定初始值的参数。*kwargs是指我们给定初始值的参数。我们可以使用*args, **kwargs,直接将一个函数的参数,传给另一个函数。
运行结果:
知识点4:函数中调用【作为参数的函数】,并返回结果
def hi(name='Andy'):
return f'hello,{name}!'
def printf(fn):
def wrapper(*args, **kwargs):
print('这里是fn的前置逻辑')
ret = fn(*args, **kwargs)
print('这里是fn的后置逻辑')
return ret
return wrapper
result = printf(hi)(name='ruby')
print(result)
运行结果:
到底什么是装饰器
讲了4个知识点终于到了核心部分,其实在知识点4中,我们已经了掌握了装饰器,只需要稍加改变就变成了一个我们想要看到的@符号装饰的代码装饰器就是对函数进行包裹后的函数,目的就是在包裹函数中处理额外的逻辑
def printf(fn):
def wrapper(*args, **kwargs):
print('这里是fn的前置逻辑')
ret = fn(*args, **kwargs)
print('这里是fn的后置逻辑')
return ret
return wrapper
@printf
def hi(name='Andy'):
return f'hello,{name}!'
result = hi(name='ruby')
print(result)
运行结果:
运行的结果是不是与知识点4的代码相同,同时我们调用的方式,做了简单,也就是我们直接调用我们的函数就可以了。
扩展:一道关于装饰器的面试题:请设计一个装饰器,他可以作用到任何函数上,并打该函数的的执行时间。
(1)定义一个函数
def hi(name='Andy'):
print(f'hello,{name}!')小提示:f开头表示在字符串内支持大括号内的python 表达式
(2)编写装饰器函数
import time, functools
def excute(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
startTime = time.time()
result = fn(*args, **kwargs)
endTime = time.time()
print(f'Function{fn.__name__}excute start: {endTime-startTime}')
return result
return wrapper小提示:@functools.wraps(fn),用来将wapper的函数相关的内置变量名,比如__name__与原有的函数保持一致。
(3)完整代码如下
import time, functools
def excute(fn):
@functools.wraps(fn)
def wrapper(*args, **kwargs):
startTime = time.time()
result = fn(*args, **kwargs)
endTime = time.time()
print(f'Function{fn.__name__}excute start: {endTime-startTime}')
return result
return wrapper
@excute
def hi(name='Andy'):
print(f'hello,{name}!')
hi(name='Ruby')
执行结果: