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()

浙公网安备 33010602011771号