简单讨论装饰器

一、闭包,装饰器 

# 一、闭包,装饰器

def w1():
    def inner():
        print('-------正在验证权限-----')
    return inner


def f1():
    print('--------f1---------')


# 1.执行w1(),此时return了inner函数,注意:目前w1函数里面的inner()函数不会被执行
# 2.innerFunc接受return值 所以实质innerFunc=inner 即innerFunc指向了inner
innerFunc = w1()
# 3.因为步骤2已经说明innerFunc指向了inner,innerFunc()就等于inner(), 所以这里打印-------正在验证权限-----
innerFunc()


# 那么需求来了,我想在inner函数中,执行f1()函数该怎么办呢?
def w1(func):
    def inner():
        print('-------正在验证权限-----')
        func()
    return inner

def f1():
    print('--------f1---------')

# 1.执行w1(f1),调用函数w1,同时把f1的引用传给参数func, 所以此时inner函数中的func()相当于f1() 然后return
# 2.innerFunc接受return值inner
innerFunc = w1(f1)

# 3. innerFunc()就等于inner(), 而inner函数中除了有个print(),还有个func() 即f1()
# 所以此时会打印-------正在验证权限----- 和 --------f1---------
innerFunc()


# 这个时候问题又来了,我原来目的是为了调用f1函数的时候,自动调用w1里面的功能,现在多出来个innerFunc 岂不是违背了目的
# 那么我们知道执行w1(f1)后会return一个值,这个值我不用innerFunc接受, 我们用xxx, yyy, 随便你起名字 可以吗?
xxx = w1(f1)
xxx()

# 验证答案是可以的,那么既然能随便起名字,那我就起成f1,不就变成了f1(),这样我就在执行f1()的时候执行了w1中的内容
f1 = w1(f1)
f1()


# 上述的所有说明就是装饰器的原理,那么有没有简单的方式呢? 这时候知识点来了

def w1(func):
    def inner():
        print('-------正在验证权限-----')
        func()
    return inner

# 这一个@w1就等价于f1 = w1(f1)
@w1
def f1():
    print('--------f1---------')

f1()

二、多个装饰器讨论

def w1(func):
    def inner():
        print('----正在执行w1-----')
        func()  # 相当于test1()
    return inner


def w2(func):
    def inner():
        print('----正在执行w2-----')
        func()  # 相当于test()
    return inner


@w1  # test = w1(test1)
@w2  # test1 = w2(test)  test1指向了w2中的inner 此时inner中有 ----正在执行w2----- 和------test-------
def test():
    print('------test-------')

test()
----正在执行w1-----
----正在执行w2-----
------test-------

解释:当程序自上而下进行到@w1时,发现@w1下面并不是一个函数,那么先不处理,继续往下走,走到@w2时,诶,发现了一个函数test,那么开始处理,由上面可知:test1指向了w2中的函数inner,那么此时inner中有----正在执行w2----- 和------test-------,接着w1(test1) 然后返回w1中的inner给test, 那么此时test里面就相当于有本身的----正在执行w1-----和test1指向的----正在执行w2----- 和------test-------。最后调用:test() 

def w1(func):
    print('-----正在装饰1----')
    def inner():
        print('----正在执行w1-----')
        func()
    return inner


def w2(func):
    print('-----正在装饰2-----')
    def inner():
        print('----正在执行w2-----')
        func()
    return inner


@w1  # 只要python解释器执行到这部分代码,就会自动装饰,不会等调用才装饰
@w2  
def test():
    print('------test-------')

# test()  注意我屏蔽了调用
-----正在装饰2-----
-----正在装饰1----

解释:上面已经说到:发现@w1下面并不是一个函数,那么先不处理,所以先处理@w2,装饰@w2完后,再装饰@w1;同时要记住只要python解释器执行到这部分代码,就会自动装饰,不会等调用才装饰。

 

def w1(func):
    print('-----正在装饰1----')
    def inner():
        print('----正在执行w1-----')
        func()
    return inner


def w2(func):
    print('-----正在装饰2-----')
    def inner():
        print('----正在执行w2-----')
        func()
    return inner


@w1  
@w2  
def test():
    print('------test-------')
-----正在装饰2-----
-----正在装饰1----
----正在执行w1-----
----正在执行w2-----
------test-------

总结:实在不清楚原理,可以简单理解为:装饰器哪个离函数近,就先装饰哪个, 执行就从上往下执行。

 

三、被装饰的函数有参数

def w1(func):
    def inner(a, b):  # 如果这里不写两个实参,那么调用test(1,2)会报错
        print('-------')
        func(a, b)  # 如果这里不写两个实参,那么调用def test(a, b):会报错
    return inner

    
@w1
def test(a, b):
    print(a+b)

test(1,2)


# 不定长参数的装饰器
def w1(func):
    def inner(*args, **kwargs):
        print('-------')
        func(*args, **kwargs)
    return inner


@w1
def test(a, b, c):
    print(a+b+c)

test(1,2,3)

四、装饰器装饰有返回值的函数

def w1(func):
    def inner():
        print('*****')
        func()
    return inner


@w1
def test():
    print('----这是测试----')
    return 'handsome'

test()  # 打印结果可发现,并没有返回handsome



def w1(func):
    def inner():
        print('*****')
        xxx = func()  # 接收返回值handsome
        return xxx  # 这里写xxx是为了便于理解,有点不规范,所以最好写成ret
    return inner


@w1
def test():
    print('----这是测试----')
    return 'handsome'

ret = test()  # 调用函数的同时接收 return xxx 返回的结果
print(ret)

五、装饰器带参数

def w(arg):
    def w1(func):
        def inner():
            print('------')
            func()
            print('arg的值是%s' % arg)
        return inner
    return w1


@w('wenwen')
def test():
    print('----test------')

test()

解释:1.先执行 w('wenwen')这个函数,这个函数return的结果就是w1这个函数的引用

           2.然后再@w1,使用@w1对test进行装饰

       

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值