python装饰器(decorator)解析

一、装饰器的基本原理

装饰器的本质就是一个函数,特别之处在于这个函数接收的对象也是函数,作用是给被装饰函数增添一些附加功能。文字描述起来比较绕,我们直接来看代码。

注意: @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)从上往下执行。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值