如何理解python装饰器

3 篇文章 0 订阅

一. @语法糖的理解

一般出现情况为:

@funcA
def funB():
    ...

转换成更容易理解的语句为:

temp = funcA(funcB)
funcB = temp

一句话总结:装饰器的本质也是一种运算符

举例1说明:

def decorator(func):
    print("in decorator")  
    print("it's func:" + str(func))
    print("out decorator")
    return 996

@decorator
def main():
    print("This is main()")

if __name__ == "__main__":
    print(type(main))
    print(main)

上面这段代码会依次打印:

in decorator
it's func:<function main at 0x037ED9C0>
out decorator
<class 'int'>
996

案例1理解:

按照说法先执行decorator(main),所以会先打印

in decorator
it's func:<function main at 0x037ED9C0>
out decorator

然后把main函数传进decorator函数,并且将返回值赋值给main,所以main就是996这个数字了。

 

二. 实际使用

我们使用装饰器的目的是为了简化代码的修改,比如我需要在所有的函数入口打印消息表示进入函数。假设原代码是这样的:

def funA():
    while True:
        pass
    print("funA")

def funB():
    raise Exception("my exception")
    print("funB")

def funC():
    a = 6
    b = 3
    c = 1
    print(a + b + c)

不使用装饰器的做法是:

def funA():
    print("in funA")
    while True:
        pass
    print("funA")

def funB():
    print("in funB")
    raise Exception("my exception")
    print("funB")

def funC():
    print("in funC")
    a = 6
    b = 3
    c = 1
    print(a + b + c)

使用装饰器的做法是:

def decorator(fun):
    def whatever():
        print("in " + str(func))
        fun()
        return
    return whatever

@decorator
def funA():
    while True:
        pass
    print("funA")

@decorator
def funB():
    raise Exception("my exception")
    print("funB")

@decorator
def funC():
    a = 6
    b = 3
    c = 1
    print(a + b + c)

可以看到这样做能够避免散弹式修改,如果后期还需要在调用这些函数前后加一些操作,直接修改decorator函数即可。比如现在又需要在函数出口打印退出函数消息,修改decorator即可

def decorator(fun):
    def whatever():
        print("in " + str(func))
        fun()
        print("out " + str(func))
        return
    return whatever

这里引用装饰器时,相当于执行以下语句

temp = decorator(funC)
func = temp

也就是说func就等同于decorator里面的函数whatever了

三. 装饰器的进阶使用

以上你已经理解了装饰器语法糖的含义,也了解了装饰器的基本使用目的,下面就介绍一下更加复杂的用法

3.1 传参数1

被装饰的函数如何传参数到装饰器里面的函数呢?可以参考一下下面的例子:

def decorator(func):
    def whatever(*sub_args, **sub_kwargs):
        print("in sub")
        func(*sub_args, **sub_kwargs)
        print("out sub")
        return
    return whatever


@decorator
# @decorator: test = decorator(test)
def test(name, subname):
    print(name + subname)

3.2 传参数2

被装饰的函数如何传参数到装饰器函数呢?可以参考一下下面的例子:

def decorator(param):
    def real_decorator(func):
        def whatever(*sub_args, **sub_kwargs):
            print("in sub")
            print(param)
            func(*sub_args, **sub_kwargs)
            print("out sub")
            return
        return whatever
    return real_decorator


@decorator(param="param")
# 先执行decorator(param="param")返回一个函数real_decorator
# 再执行@real_decorator,相当于执行test = real_decorator(test)
def test(name, subname):
    print(name + subname)

详解

名称后面加小括号表示调用,优先级高于装饰器语法糖,所以先执行调用,再进行装饰

@decorator(param="param")
def test(name, subname):

            ||
            \/

test = decorator(param="param")(test)

            ||
            \/

temp = decorator(param="param")
test = temp(test)

3.3 多重装饰器

如果使用多重装饰器,怎么判断执行的先后顺序呢?参考下面的例子:
 
def decorator1(func):
    print('in decorator1')
    
    def whatever1():
        print('in whatever1')
        return func()

    return whatever1


def decorator2(func):
    print('in decorator2')

    def whatever2():
        print('in whatever2')
        return func()

    return whatever2


@decorator1
@decorator2
def test():
    print('test result')


test()

依次输出:

in decorator2
in decorator1
in whatever1
in whatever2
test result

详解:

@decorator1
@decorator2
def test():
代码从上向下执行,相当于执行
test = decorator1(@decorator2
                  def test():)

            ||
            \/

test = decorator1(decorator2(test))

3.4 让被装饰函数表示自己

不表示自己时:

def decorator(func):
    def whatever(*sub_args, **sub_kwargs):
        print("in sub")
        func(*sub_args, **sub_kwargs)
        print("out sub")
        return
    return whatever


@decorator
# @decorator: test = decorator(test)
def test(name, subname):
    print(name + subname)


print(test)

打印结果:<function decorator.<locals>.whatever at 0x0147D9C0>

 

表示自己需要借助其他函数:

import functools


def decorator(func):
    @functools.wraps(func)
    def whatever(*sub_args, **sub_kwargs):
        print("in sub")
        func(*sub_args, **sub_kwargs)
        print("out sub")
        return
    return whatever


@decorator
# @decorator: test = decorator(test)
def test(name, subname):
    print(name + subname)


print(test)

打印结果:<function test at 0x00BDDC48>

 

 

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值