装饰器
装饰器是经常用到的功能,很多面试都会问到,使用也是功能很强大。
本篇介绍了无参数和不定长参数的函数使用装饰器,带参数的装饰器,多重装饰器以及类装饰器。
装饰器常用场景
- 引入日志
- 函数执行时间
- 执行函数的预处理
- 执行函数后的清理
- 权限校验
- 缓存
例1:入门装饰器(无参数装饰器)
上代码:
def w1(func):
def inner():
print('this is one')
print('------------------')
return func()
return inner # 返回inner函数
@w1
def f1():
print('this is two')
# 调用函数f1
f1()
执行结果:
执行步骤:
- python解释器会先def w1(func) ,w1函数加载到内存中
- @w1
在函数调用之前其内部的代码不会被执行。但是@w1语句,包含很多的内容。@函数名是python的一种语法糖。
@w1会执行以下操作:
- 执行w1函数,并且将@符号下面的函数作为w1函数的参数,即@w1=w1(f1)。
此时就会去调用并执行w1(func)函数,解释器首先加载的是inner函数,而不是执行(因为没有调用) - 当执行到return inner时候,才会调用函数inner()函数,在函数inner中依次执行,执行到return func(),此时func() = f1()。即调用函数f1(),则是调用函数inner(),
- 调用inner函数是,因为func() = f1(),所以才会执行函数f1()。
例2:被装饰的函数带不定长参数
上代码:
from time import ctime, sleep
def timefun(func):
def inner(*args, **kwagrs): # 使用 *args, **kwagrs接受参数
print('%s called at %s' %(func.__name__, ctime()))
return func(*args, **kwagrs) # func函数也要加上*args, **kwagrs
return inner
@timefun
def foo(a, b, c):
print(a+b+c)
foo(1, 2, 3)
sleep(3)
foo(9, 8, 7)
获取结果:
在inner函数出使用*args, kwagrs接受不定长以及关键字参数。
注意**:
- inner函数中使用的func.name输出的是函数foo的函数名,如果只是使用func,则是输出是函数的内存地址。
- return func() return必须加上,为了让装饰器更通用。以防在执行函数foo()处没有print而是renturn的时候,就不会输出结果。
- ctime()方法返回的是当前的时间
例3:装饰器带参数
在原有装饰器的基础上,设置外部变量。
上代码:
from time import ctime, sleep
def timefun_arg(pre='hello'): # 装饰器参数在这里接受,里面嵌套的函数可以直接使用
def timefunc(func): # 以下内容和装饰器不带参数的形式形同
def inner(*args, **kwagrs):
print('%s called at %s %s' % (func.__name__, ctime(), pre))
return func(*args, **kwagrs)
return inner # 返回inner函数
return timefunc # 返回timefunc函数
@timefun_arg('Python') # 装饰器参数在这里传递
def foo(a, b, c):
print(a+b+c)
foo(1, 3, 4)
sleep(2)
foo(7, 8, 9)
输出结果:
例4:多重装饰器
@A
@B
def c():
pass
装饰的时候先是用B装饰,再用A装饰。
在执行时候,先执行A函数,再执行B函数。
当执行A是,需要return func即c函数,此时的c函数放在了B中的return func()中了,因为先装饰最近的函数,所以返回给A的内容中,是已经加上B中的内容以后的。
上代码:
def makeBold(fn):
def wrapped():
return "<b>" + fn() + "</b>"
return wrapped
def makeItalic(fn):
def wrapped():
return "<i>" + fn() + "</i>"
return wrapped
@makeBold
@makeItalic
def test3():
return "hello world-3"
运行结果:
<b><i>hello world-3</i></b>
例6:类装饰器
参考链接:
http://howdoit.cn/2017/03/16/09-python-%E7%B1%BB%E8%A3%85%E9%A5%B0%E5%99%A8/
待补充,敬请期待