简述Python中装饰器的原理及用法

想要弄懂Python中的装饰器,首先需要知道什么是闭包,比较正式的说法:将组成的函数语句和这些语句的执行环境(所需变量等)打包在一起,得到的对象称之为闭包。
构成闭包必备条件:①必须要有内嵌函数、②内嵌函数必须外部嵌套函数中的变量;③外部嵌套函数的返回值必须是内嵌函数名。
程序应该遵循开放封闭原则,虽然这个原则用于的面向对象开发,但是也适用函数式编程,简单来说,它规定了已经实现的功能代码不允许被修改,但是可以被扩展,也即:封闭(已实现的功能代码块)、开放(对扩展开发)。
装饰器在不用修改原函数代码情况下,就可以给原函数(在函数整体之前或之后)添加新功能(不能实现在原函数内部添加新功能),并且在调用的时候和原来调用一模一样,这里需要注意的是,装饰器是基于闭包环境存在的。
下面就通过代码讲解装饰器在各种场景中的应用:
情况1:对没有参数没有返回值的函数装饰

# ============= 闭包环境 ============ #
def set_function(fun):
    def call_function():
        print('---权限验证---')
        fun()
    return call_function
# =================================== #

@set_function
def test1():
    print('---test1---')

test1()

# 输出结果:
# ---权限验证---
# ---test1---

# 说明:@set_function 等价于:test1 = set_function( test1)   
# 需要注意的是:只要执行到@set_function的时候,其实就已经开始装饰了。
# 而不是到了test1()的时候才开始装饰,也就是说装饰器在函数被调用之前就已经装饰完毕了。

情况2:对有参数无返回值的函数装饰

def set_function(fun):
    def call_function(a):
        print('---权限验证---')
        fun(a)
    return call_function

@set_function
def test1(num):
    print('---test1---:%d' %num)

test1(100)

# 输出结果:
# ---权限验证---
# ---test1---:100

# 说明:100传递给call_function(a)的形参a,fun(a)将a传递给test1(num)中的形参num。

情况3:对带有不定长参数或缺省参数装饰

def set_function(fun):
    print('---开始进行装饰---')
    def call_function(*args, **kwargs):
        print('---权限验证---')
        fun(*args, **kwargs)
    return call_function

@set_function
def test1(num, *args, **kwargs):
    print('---test1---')
    print(num, args, kwargs)

test1(100)
test1(100, 200)
test1(100, 200, m=300)

# 输出结果:
# ---开始进行装饰---
# ---权限验证---
# ---test1---
# 100 () {}
# ---权限验证---
# ---test1---
# 100 (200,) {}
# ---权限验证---
# ---test1---
# 100 (200,) {'m': 300}

情况4:对带有返回值的函数装饰(1)

def set_function(fun):
    print('---开始进行装饰---')
    def call_function(*args, **kwargs):
        print('---权限验证---')
        fun(*args, **kwargs)
    return call_function

@set_function
def test1(num, *args, **kwargs):
    print('---test1---')
    print(num, args, kwargs)
    return '200','ok'

ret = test1(100)
print(ret)

# 输出结果:
# ---开始进行装饰---
# ---权限验证---
# ---test1---
# 100 () {}
# None

情况5:对带有返回值的函数装饰(2)

def set_function(fun):
    print('---开始进行装饰---')
    def call_function(*args, **kwargs):
        print('---权限验证---')
        return fun(*args, **kwargs)
    return call_function

@set_function
def test1(num, *args, **kwargs):
    print('---test1---')
    print(num, args, kwargs)
    return '200','ok'

# ret = test1(100)
# print(ret)

# 输出结果:
# ---开始进行装饰---
# ---权限验证---
# ---test1---
# 100 () {}
# ('200', 'ok')

# 说明:
# return None 相当于 None 也相当于函数没有返回值(无return语句)。

情况6:多个装饰器对同一个函数装饰

def set_function1(fun):
    print('---开始进行装饰1---')
    def call_function1(*args, **kwargs):
        print('---权限1验证---')
        return fun(*args, **kwargs)
    return call_function1

def set_function2(fun):
    print('---开始进行装饰2---')
    def call_function2(*args, **kwargs):
        print('---权限2验证---')
        return fun(*args, **kwargs)
    return call_function2

@set_function1
@set_function2
def test1(num, *args, **kwargs):
    print('---test1---')
    print(num, args, kwargs)

# ret = test1(100)
# print(ret)

# 输出结果:
# ---开始进行装饰2---
# ---开始进行装饰1---
# ---权限1验证---
# ---权限2验证---
# ---test1---
# 100 () {}
# None

# 意义:对同一个函数可以加多种不同的功能,并且将功能分散在各个装饰器中。

下面针对情况6,给出函数相互之间的调用顺序,当执行至print(ret):
step1:程序首先会执行set_function2(fun)函数,此时fun接受的实参是函数名test1;
step2:print(’—开始进行装饰2—’)
step3:然后执行set_function1(fun)函数,此时fun接受的实参是函数名test1;
step4:print(’—开始进行装饰1—’)
step5:执行call_function1()函数,print(’—权限1验证—’), 在实际工程中,可以在这里添加 你的业务代码块;
step6:执行call_function2()函数,print(’—权限2验证—’) , 在这里添加业务代码块;
step7: 最后执行test1()函数,print(’—test1—’).

情况7:应用装饰器类对函数进行装饰

class Test(object):
    def __init__(self, func):
        self.function = func

    def __call__(self):
        print('--此处添加额外功能--')
        return self.function

@Test  # get_str = Test(get_str)
def get_str():
    return 'ok'

ret=get_str()  # 调用__call__方法。ret 此时绑定self.function所绑定的func。

print(ret())

# 输出结果:
# --此处添加额外功能--
# ok

情况8:带有参数的装饰器对函数进行装饰

def set_level(level_num):
    def set_func(func):
        def call_func(*args, **kwargs):
            if level_num == 1:
                print('----验证权限1----')
            elif level_num == 2:
                print('----验证权限2----')
            return func()
        return call_func
    return set_func


@set_level(1)
def test1():
    print('----test1----')
    return 'ok'

@set_level(2)
def test2():
    print('----test2----')
    return 'bye'

test1()
test2()

# 输出结果:
# ----验证权限1----
# ----test----
# ----验证权限2----
# ----test2----

# 说明:
# 当运行至@set_level(1)时,程序会将1当做实参传递,并且将用set_level函数的返回值对test1
# 函数进行装饰,最终test1也指向call_func函数。
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值