您的位置:首页 > 编程语言 > Python开发

Python装饰器(函数层面)

2020-04-20 18:40 211 查看

装饰器功能

装饰器是做什么的呢,简单的说装饰器可以为函数添加功能却不改变函数本身任何源码。说到这里你可能还是对装饰器的功能不是很懂,那么思考下面一个问题。 怎么在不改变源码的情况下实现plus 对x+2呢?

def plus(x):
return x+1
if __name__ == "__main__":
#不改变源码的情况下实现 让plus返回x+2
print(plus(1))

函数装饰函数

单层装饰

单层有参函数的简易装饰

对于Python这么好用的语言,答案肯定是有的,先来看下面一段代码吧。

def add_func(func):
def inner(x):#装饰函数
a = func(x)
return a+1
return inner
@add_func
def plus(x):
return x+1
if __name__ == "__main__":
#不改变源码和调用关系的情况下实现 让plus做到x+2
print(plus(1))

接下来就让我们分析一下上面的代码吧:
首先对于@add_func这个符号怎么去理解呢,首先@是一个修饰符,修饰符怎么去理解呢,修饰符@后面的函数去调用下面被修饰的函数。
所以修饰符的大概功能是plus = add_func(plus)。我们如果把上面代码中的@去掉,然后用下面两行代码在main中实现也是可以实现答案的

plus = add_func(plus)
print(plus(1))

具体的原理就是Python对于任何变量的名字返回的都是地址,对于地址是函数的变量来说,在变量的末尾加上(),就可以实现函数的功能了。所以在add_func(plus)的意思就是把plus函数的地址放到add_func的参数中去,这样返回出来的值就是inner , 对于inner来说 他是inner函数的地址,这个函数实现了对plus返回值加1就是把x加1的功能,所以我们把inner函数的地址又赋值给了plus这个变量。这样一来,plus()实际上是执行了add_func.inner()这个函数。

单层无参函数的简易装饰

这一功能最常见的用处是用来验证所执行的权限。原理已经在上面具体阐述过了,所以我们就实现简单的demo来知道处理的机制就可以了。

def add_func(func):
def wrap():
print("在这个位置实现登录的权限验证")
func()
print("在这里可以处理登录完成后的事项")
return wrap
@add_func
def login():
print("登录成功")
if __name__ == "__main__":
#不改变源码和调用关系的情况下实现 让login可以验证登录
login()
多适应装饰器

现在我们的需求在登录的基础上改变,因为我们的网站效益高,我们开通了vip渠道,来为vip提供更加优质的服务,并且服务会根据vip的等级不同而有区分。所以我们需要实现两个函数 login() vip_login(vip_level),之前的login我们已经实现好了,难道我们又为vip_login单独写一个装饰器在装饰函数上加上变量吗。先看下面代码.

def add_func(func):
def wrap(*args,**kwargs):
print("在这个位置实现登录的权限验证")
func(*args,**kwargs)
print("在这里可以处理登录完成后的事项")
return wrap
@add_func
def login():
print("登录成功")

@add_func
def vip_login(vip_level):
print("vip登录成功,您的当前等级"+str(vip_level))
if __name__ == "__main__":
#login()
vip_login(1)

答案非常简单,我们在装饰函数的参数列表中加入万能的适应参数就可以解决了,有不懂的小伙伴可以自己去查阅一下资料,这里不做解释了。
这样一来,我们的一个装饰器可以对许许多多的函数增加功能还不破坏他们的源码。

多层装饰器

如果会用单层装饰器,其实已经可以解决大多数情况了,那如果我们要好好理解一下装饰器的详细原理的话就可以通过一个双层的装饰器来进行研究。

def yu_lang_long(fun): #2 装饰 makeItalic.inner()
print('----狱狼龙装饰阶段----')
def inner():
print('----狱狼龙执行阶段----')
return '<狱狼龙>' + fun() + '</狱狼龙>'

return inner  #3  test 被装饰成 makeBold.inner()  注意此时的test
def lei_lang_long(fun):
print('----雷狼龙装饰阶段----')
def inner():
print('----雷狼龙执行阶段----')
return '<雷狼龙>' + fun() + '</雷狼龙>'
return inner  # 1
@yu_lang_long
@lei_lang_long
def shou_lie():
print('----狩猎执行阶段----')
return '狩猎完成'
print(shou_lie())

输出:

----雷狼龙装饰阶段----
----狱狼龙装饰阶段----
----狱狼龙执行阶段----
----雷狼龙执行阶段----
----狩猎执行阶段----
<狱狼龙><雷狼龙>狩猎完成</雷狼龙></狱狼龙>
  1. 装饰时机 通过上面装饰时机的介绍,我们可以知道,在执行到@yu_lang_long的时候,需要对下面的函数进行装饰,此时解释器继续往下走,发现并不是一个函数名,而是一个装饰器,这时候,@yu_lang_long装饰器暂停执行,而接着执行接下来的装饰器@lei_lang_long,这时候解释器发现下面是一个函数,所以就把shou_lie这个函数地址传递给lei_lang_long,所以就输出了雷狼龙装饰阶段,经过装饰的函数这下可以被解释器识别了,所以继续进行狱狼龙的装饰。装饰完成后,就应该执行shou_lie()这个函数了。
  2. 执行步骤 我们再把思路捋一遍,狩猎函数先被雷狼龙装饰,装饰完成后被狱狼龙装饰,然后开始执行。所以现在执行的就是狱狼龙的装饰函数,所以打印出狱狼龙执行阶段,下面的fun 实际上是被 雷狼龙装饰的狩猎函数,所以打印出来的雷狼龙执行阶段,雷狼龙装饰函数里面的fun就是实际的狩猎函数了所以打印出来的就是狩猎执行阶段。
  3. 回溯步骤 执行完了,就要从底层函数一层一层回溯当上层,先是狩猎阶段,然后是雷狼龙,然后是狱狼龙。至此装饰函数执行完毕。

有关类的装饰问题会在以后的过程中继续学习总结

  • 点赞
  • 收藏
  • 分享
  • 文章举报
QiQi-OvO 发布了3 篇原创文章 · 获赞 2 · 访问量 266 私信 关注
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: