Python:Day:python 装饰器复习

装饰器进阶

现在,我们已经明白了装饰器的原理。接下来,我们还有很多事情需要搞清楚。比如:装饰带参数的函数、多个装饰器同时装饰一个函数、带参数的装饰器和类装饰器。

装饰带参数函数

 1 def foo(func):  # 接收的参数是一个函数名
 2     def bar(x, y):  # 这里需要定义和被装饰函数相同的参数
 3         print("这里是新功能...")  # 新功能
 4         func(x, y)  # 被装饰函数名和参数都有了,就能执行被装饰函数了
 5     return bar
 6 
 7 
 8 # 定义一个需要两个参数的函数
 9 @foo
10 def f1(x, y):
11     print("{}+{}={}".format(x, y, x+y))
12 
13 
14 # 调用被装饰函数
15 f1(100, 200)
16 输出:
17 
18 这里是新功能...
19 100+200=300

 

多个装饰器

 1 def foo1(func):
 2     print("d1")
 3 
 4     def inner1():
 5         print("inner1")
 6         return "<i>{}</i>".format(func())
 7 
 8     return inner1
 9 
10 
11 def foo2(func):
12     print("d2")
13 
14     def inner2():
15         print("inner2")
16         return "<b>{}</b>".format(func())
17 
18     return inner2
19 
20 
21 @foo1
22 @foo2
23 def f1():
24     return "Hello Andy"
25 
26 # f1 = foo2(f1)  ==> print("d2") ==> f1 = inner2
27 # f1 = foo1(f1)  ==> print("d1") ==> f1 = foo1(inner2) ==> inner1
28 
29 ret = f1()  # 调用f1() ==> inner1()  ==> <i>inner2()</i>  ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i>
30 print(ret)

 

带参数装饰器

被装饰的函数可以带参数,装饰器同样也可以带参数。

回头看我们上面写得那些装饰器,它们默认把被装饰的函数当成唯一的参数。但是呢,有时候我们需要为我们的装饰器传递参数,这种情况下应该怎么办呢?

接下来,我们就一步步实现带参数的装饰器:

首先我们来回顾下上面的代码:

1 def f1(func):  # f1是我们定义的装饰器函数,func是被装饰的函数
2     def f2(*arg, **kwargs):  # *args和**kwargs是被装饰函数的参数
3         func(*arg, **kwargs)
4     return f2

 

从上面的代码,我们发现了什么?

我的装饰器如果有参数的话,没地方写了…怎么办呢?

还是要使用闭包函数!

我们需要知道,函数除了可以嵌套两层,还能嵌套更多层:

1 # 三层嵌套的函数1
2 def f1():    
3     def f2():
4         name = "Andy"       
5         def f3():
6             print(name)
7         return f3    
8     return f2

 

嵌套三层之后的函数调用:

1 f = f1()  # f --> f2
2 ff = f()  # ff --> f3
3 ff()  # ff()  --> f3()  --> print(name)  --> Andy

 

注意:在内部函数f3中能够访问到它外层函数f2中定义的变量,当然也可以访问到它最外层函数f1中定义的变量。

1 # 三层嵌套的函数2
2 def f1():
3     name = "Andy"
4     def f2():
5         def f3():
6             print(name)
7         return f3
8     return f2

 

调用:

1 f = f1()  # f --> f2
2 ff = f()  # ff --> f3
3 ff()  # ff()  --> f3()  --> print(name)  --> Andy

 

好了,现在我们就可以实现我们的带参数的装饰器函数了:

1 # 带参数的装饰器需要定义一个三层的嵌套函数
2 def d(name):  # d是新添加的最外层函数,为我们原来的装饰器传递参数,name就是我们要传递的函数
3     def f1(func):  # f1是我们原来的装饰器函数,func是被装饰的函数
4         def f2(*arg, **kwargs):  # f2是内部函数,*args和**kwargs是被装饰函数的参数
5             print(name)  # 使用装饰器函数的参数
6             func(*arg, **kwargs)  # 调用被装饰的函数
7         return f2
8     return f1

 

上面就是一个带参装饰器的代码示例,现在我们来写一个完整的应用:

 1 def d(a=None):  # 定义一个外层函数,给装饰器传参数--role
 2     def foo(func):  # foo是我们原来的装饰器函数,func是被装饰的函数
 3         def bar(*args, **kwargs):  # args和kwargs是被装饰器函数的参数
 4             # 根据装饰器的参数做一些逻辑判断
 5             if a:
 6                 print("欢迎来到{}页面。".format(a))
 7             else:
 8                 print("欢迎来到首页。")
 9             # 调用被装饰的函数,接收参数args和kwargs
10             func(*args, **kwargs)
11         return bar
12     return foo
13 
14 
15 @d()  # 不给装饰器传参数,使用默认的'None'参数
16 def index(name):
17     print("Hello {}.".format(name))
18 
19 
20 @d("电影")  # 给装饰器传一个'电影'参数
21 def movie(name):
22     print("Hello {}.".format(name))
23 
24 if __name__ == '__main__':
25     index("Andy")
26     movie("Andy")
27 输出:
28 
29 欢迎来到首页。
30 Hello Andy.
31 欢迎来到电影页面。
32 Hello Andy.

 

类装饰器和装饰类

类装饰器

除了用函数去装饰函数外,我们还可以使用类去装饰函数。

 1 class D(object):
 2     def __init__(self, a=None):
 3         self.a = a
 4         self.mode = "装饰"
 5 
 6     def __call__(self, *args, **kwargs):
 7         if self.mode == "装饰":
 8             self.func = args[0]  # 默认第一个参数是被装饰的函数
 9             self.mode = "调用"
10             return self
11         # 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行)
12         if self.a:
13             print("欢迎来到{}页面。".format(self.a))
14         else:
15             print("欢迎来到首页。")
16         self.func(*args, **kwargs)
17 
18 
19 @D()
20 def index(name):
21     print("Hello {}.".format(name))
22 
23 
24 @D("电影")
25 def movie(name):
26     print("Hello {}.".format(name))
27 
28 if __name__ == '__main__':
29     index("Andy")
30     movie("Andy")

 

装饰类

我们上面所有的例子都是装饰一个函数,返回一个可执行函数。Python中的装饰器除了能装饰函数外,还能装饰类。

可以使用装饰器,来批量修改被装饰类的某些方法:

 1 # 定义一个类装饰器
 2 class D(object):
 3     def __call__(self, cls):
 4         class Inner(cls):
 5             # 重写被装饰类的f方法
 6             def f(self):
 7                 print("Hello Andy.")
 8         return Inner
 9 
10 
11 @D()
12 class C(object):  # 被装饰的类
13     # 有一个实例方法
14     def f(self):
15         print("Hello world.")
16 
17 
18 if __name__ == '__main__':
19     c = C()
20     c.f()

 

posted @ 2018-10-12 16:42  毛丫头  阅读(105)  评论(0)    收藏  举报