python装饰器

python装饰器

函数闭包:函数内部嵌套函数

闭包举例:

def w():
    print("闪开,我要开始装逼了")
    def f():
        print("hello world!")
    return f

# 调用:
res = w()
res()
# 或w()()

​ 闭包就是在一个函数内部再定义一个函数,外部的函数返回内部函数名。这样,仅仅调用外部函数得到的就只是执行非内部函数部分的函数体,并返回一个内部函数名。因作用域的关系,外部函数体以外是调用不到内部函数的。所以为了能够在外部调用到,外部函数体返回的是内部函数的函数名而不加括号,这样就可以在外部调用内部函数时更加灵活(如向内部函数传参)。

装饰器原理:闭包的内部函数调用被装饰的函数

​ 装饰器实际上也是一个闭包,在闭包的内部函数中调用被封装的函数,并添加需要装饰的功能。这样,一个装饰器函数就写好了,然后@符号加外部函数名就是装饰器。定义被装饰函数时,将装饰器写在被装饰函数上面就行了。

# 定义装饰器
def zhuangshiqi(fun):
    print("装饰一下")
    def inner():
        print("在这里添加一些装饰内容")
        fun()
    return inner
# 使用装饰器
@zhuangshiqi
def beizhuangshihanshu():
    print("被装饰函数的内容")

# 调用被装饰后的函数
beizhuangshihanshu()

由此可以发现,当python解释器执行到@zhuangshiqi时,就开始进行装饰了,相当于执行了如下代码

beizhuangshihanshu = zhuangshiqi(beizhuangshihanshu)

两个装饰器执行流程和装饰结果

def zhaungshiqi_01(fun_01):
    print('----a----')
    def inner_01():
        print('----1----')
        return '<b>' + fun_01() + '</b>'
    return inner
def zhuangshiqi_02(fun_02):
    print('----b----')
    def inner_02():
        print('----2----')
        return '<i>' + fun_02() + '</i>'
    return inner

@zhaungshiqi_01
@zhuangshiqi_02
def test():
    print('----c----')
    print('----3----')
    return 'hello world'
ret = test()
print(ret)

先看执行结果:

----b----
----a----
----1----
----2----
----c----
----3----
<b><i>hello python decorator</i></b>

**实现顺序:**第二个装饰器@zhuangshiqi_02先进行装饰 ——> 第一个装饰器@zhaungshiqi_01再进行装饰 ——>执行第一个装饰器内部函数 ——>执行第二个装饰器内部函数

原因分析:

1、由内及外:当代码运行到第一个装饰器@zhaungshiqi_01时,本来应该是对下面的函数进行装饰,而此时代码往下走后紧接着的并不是一个函数,而是又一个装饰器。这时候装饰器@zhaungshiqi_01暂停执行,接着执行下面的装饰器@zhuangshiqi_02。然后被装饰函数test传入到装饰器函数zhuangshiqi_02中,执行zhuangshiqi_02装饰内容“print(‘----b----’)”,zhuangshiqi_02在完成装饰后,将已经被装饰过一次的test函数传给外层的装饰器函数zhaungshiqi_01,执行zhaungshiqi_01装饰内容“print(‘----a----’)”

2、再由外及内:根据由内及外原则,此时的test是位于最外层装饰器函数zhaungshiqi_01的内部函数inner_01()处,执行"print(‘----1----’)",然后调用fun_01()。而此时的fun_01()实际上是inner_02(),即先执行“print(‘----2----’)”,再调用fun_02()。fun_02()才是test(),所以执行“print(‘----c----’)”、“print(‘----3----’)”、“return ‘hello python decorator’”。层层调用之后,结果为b标签里面套i标签,再套hello world

对有参数的函数进行装饰:内部函数参数与被装饰函数参数保持一致

​ 我们应该知道,装饰器函数的外部函数是用来接收被装饰函数名的,调用被装饰函数是在内部函数。那么如果被装饰函数有参数,也应该是在调用的时候传给它。所以,装饰器函数之内部函数的参数应该与被装饰函数的参数保持一致。当然,这里说的参数保持一致是指形参的数量、类型等保持一致。

def say_hi(fun):
    def inner(name):
        print("你好!")
        fun(name)
    return inner

@say_hi
def short_name(name):
    print(f"你就是小{name[0]}吧")
    
short_name("王富贵")

​ 还记得本文开头提到的装饰器原理吗?既然short_name = say_hi(short_name),那么short_name(name)自然就等于say_hi(short_name)(name),即被装饰器的参数先传给了装饰器函数的内部函数inner(),然后再由内部函数将参数传给被调用的函数。

​ 注意:如果被装饰的函数有返回值,那么装饰器函数的内部函数也应该先接收再返回

def zhuangshiqi(fun):
    print("装饰一下")
    def inner(n):
        num = fun(n)
        return num
    return inner

@zhuangshiqi
def jiecheng(n):
    assert n >= 0 and type(n) == int,"不能阶乘"
    if n == 1 or n == 0:
        return 1
    else:
        return n * jiecheng(n-1)

引申:装饰器的使用频率很高,而被装饰函数的参数数量不一怎么破?可变参数*args,关键字参数**kwargs了解一下

def zhuangshiqi(fun):
    print("装饰一下")
    def inner(*args,**kwargs):
        num = fun(*args,**kwargs)
        return num
    return inner
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值