首页 > 编程语言 > 详细

Python 函数装饰器及用法(超级详细)

时间:2021-03-29 14:07:18      阅读:14      评论:0      收藏:0      [点我收藏+]

函数装饰器的工作原理,假设用 funA() 函数装饰器去装饰 funB() 函数,如下所示:

 1 #funA 作为装饰器函数
 2 def funA(fn):
 3     #...
 4     fn() # 执行传入的fn参数
 5     #...
 6     return ...
 7 
 8 @funA
 9 def funB():
10     #...

实际上,上面程序完全等价于下面的程序:

 1 def funA(fn):
 2     #...
 3     fn() # 执行传入的fn参数
 4     #...
 5     return ...
 6 
 7 def funB():
 8     #...
 9 
10 funB = funA(funB)

通过比对以上 2 段程序不难发现,使用函数装饰器 A() 去装饰另一个函数 B(),其底层执行了如下 2 步操作:

  1. 将 B 作为参数传给 A() 函数;
  2. 将 A() 函数执行完成的返回值反馈回  B。

举个实例:

 1 #funA 作为装饰器函数
 2 def funA(fn):
 3     print("努力学习")
 4     fn() # 执行传入的fn参数
 5     print("123")
 6     return "装饰器函数的返回值"
 7 
 8 @funA
 9 def funB():
10     print("学习 Python")

程序执行流程为:

努力学习
学习 Python
123
在此基础上,如果在程序末尾添加如下语句:
1 print(funB)

其输出结果为:

装饰器函数的返回值

显然,被“@函数”修饰的函数不再是原来的函数,而是被替换成一个新的东西(取决于装饰器的返回值),即如果装饰器函数的返回值为普通变量,那么被修饰的函数名就变成了变量名;同样,如果装饰器返回的是一个函数的名称,那么被修饰的函数名依然表示一个函数。

实际上,所谓函数装饰器,就是通过装饰器函数,在不修改原函数的前提下,来对函数的功能进行合理的扩充。

 

带参数的函数装饰器

在分析 funA() 函数装饰器和 funB() 函数的关系时,细心的人可能会发现一个问题,即当 funB() 函数无参数时,可以直接将 funB 作为 funA() 的参数传入。但是,如果被修饰的函数本身带有参数,那应该如何传值呢?

比较简单的解决方法就是在函数装饰器中嵌套一个函数,该函数带有的参数个数和被装饰器修饰的函数相同。例如:

 1 def funA(fn):
 2     # 定义一个嵌套函数
 3     def say(arc):
 4         print("Python:",arc)
 5     return say
 6 
 7 @funA
 8 def funB(arc):
 9     print("funB():", a)
10 funB("努力学习")

程序执行结果为:

Python:努力学习

分析一下这个程序,其实,它和如下程序是等价的:

 1 def funA(fn):
 2     # 定义一个嵌套函数
 3     def say(arc):
 4         print("Python:",arc)
 5     return say
 6 
 7 def funB(arc):
 8     print("funB():", a)
 9    
10 funB = funA(funB)
11 funB("学习")

如果运行此程序会发现,它的输出结果和上面程序相同。

显然,通过 funB() 函数被装饰器 funA() 修饰,funB 就被赋值为 say。这意味着,虽然我们在程序显式调用的是 funB() 函数,但其实执行的是装饰器嵌套的 say() 函数。

但还有一个问题需要解决,即如果当前程序中,有多个(≥ 2)函数被同一个装饰器函数修饰,这些函数带有的参数个数并不相等,怎么办呢?

最简单的解决方式是用 *args 和 **kwargs 作为装饰器内部嵌套函数的参数,*args 和 **kwargs 表示接受任意数量和类型的参数。举个例子:

 1 def funA(fn):
 2     # 定义一个嵌套函数
 3     def say(*args,**kwargs):
 4         fn(*args,**kwargs)
 5     return say
 6 
 7 @funA
 8 def funB(arc):
 9     print("python:",arc)
10 
11 @funA
12 def other_funB(name,arc):
13     print(name,arc)
14 funB("学习")
15 other_funB("Python:","学习")

运行结果为:

Python:学习

 

Python 函数装饰器及用法(超级详细)

原文:https://www.cnblogs.com/Outsider07/p/14591794.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!