一、装饰器的基本原理
装饰器的本质就是一个函数,特别之处在于这个函数接收的对象也是函数,作用是给被装饰函数增添一些附加功能。文字描述起来比较绕,我们直接来看代码。
注意: @decorator(func) equal to func=decorator(func)
def f(x):
print ('The result is ')
print( x * 2)
f(2)
这是一将参数乘以2的函数。这个参数可以是数字,也可以是字符串或者列表、元组,但是不可以是字典(因为字典的键不可重复)。如果我想给这个函数添加判断参数类型的功能,我可以使用装饰器。(为什么使用装饰器,而不直接在函数中使用print(type(x)))呢?因为装饰器可以用到任意想用的函数,具有很强的扩展性,也可以根据实际情况决定要不要所添加的功能,具有灵活性)。
def decorator(func):
def leixing(x):
print(type(x))
return func(x)
return leixing
#@decorator
def f(x):
print ('The result is ')
print( x * 2)
f=decorator(f)
二、多层装饰器是怎么执行的
以上是简单的装饰器的例子,只为演示装饰器的原理。装饰器可以是一层,也可以是多层。装饰器函数也有 外层函数和内层函数。
def decorator_a(func):
print ('Get in decorator_a')##外层函数
def inner_a(*args, **kwargs):
print ('Get in inner_a')##内层函数
return func(*args, **kwargs)
return inner_a
def decorator_b(func):
print ('Get in decorator_b')
def inner_b(*args, **kwargs):
print ('Get in inner_b')
return func(*args, **kwargs)
return inner_b
@decorator_b
@decorator_a
def f(x):
print ('Get in f')
return x * 2
f(3)
怎么去分析现在函数的执行情况呢?
多层装饰器的外层函数是由下往上执行的。
先有f=decorator_a(f)
f=decorator_b(f)
所以先回执行 print (‘Get in decorator_a’)
print (‘Get in decorator_b’)
此时执行f(3)函数,内存指针先指向inner_b函数,inner_b函数又指向inner_a,inner_a又指向f(3)
所以内部函数的执行是由上至下的。
结果如图:
三、functools.wraps的妙用
使用装饰器后我们可以发现内存指针所指的函数发生了变化,函数名也发生了变化.print(f)
结果为<function decorator_b.<locals>.inner_b at 0x0000000002F72840>
help(f)
结果为inner_b(*args, **kwargs)
为了消除这种影响,我们使用functools.wraps装饰包装器。
`from functools import wraps
def decorator_a(func):
print ('Get in decorator_a')
@wraps(func)
def inner_a(*args, **kwargs):
print ('Get in inner_a')
return func(*args, **kwargs)
return inner_a
@decorator_a
def f(x):
print ('Get in f')
return( x * 2)
f('iiioiii')
print(f)
help(f)
`
结果为:
Get in decorator_a
Get in inner_a
Get in f
<function f at 0x0000000002F72730>
Help on function f in module __main__:
f(x)
可想而知wraps的源码肯定是一段修改函数指针的代码。
四、总结
总而言之,对于受到封装的原函数来说,装饰器能够在那个函数执行前或者执行后分别运行一些代码,使得可以在装饰器里面访问并修改原函数的参数以及返回值,以实现约束定义、调试程序、注册函数等目标。装饰器一般返回一个包装器(wrapper),而functools.wraps就是装饰包装器的装饰器,使其函数名和地址不发生变化。当有多层装饰器时,外层函数由下往上执行,包装器(wrapper)从上往下执行。