装饰器进阶

如今,咱们已经明白了装饰器的原理。接下来,咱们还有不少事情须要搞清楚。好比:装饰带参数的函数、多个装饰器同时装饰一个函数、带参数的装饰器和类装饰器。python

装饰带参数函数

def foo(func): # 接收的参数是一个函数名 def bar(x, y): # 这里须要定义和被装饰函数相同的参数 print("这里是新功能...") # 新功能 func(x, y) # 被装饰函数名和参数都有了,就能执行被装饰函数了 return bar # 定义一个须要两个参数的函数 @foo def f1(x, y): print("{}+{}={}".format(x, y, x+y)) # 调用被装饰函数 f1(100, 200) 

输出:闭包

这里是新功能...
100+200=300 

多个装饰器

def foo1(func): print("d1") def inner1(): print("inner1") return "<i>{}</i>".format(func()) return inner1 def foo2(func): print("d2") def inner2(): print("inner2") return "<b>{}</b>".format(func()) return inner2 @foo1 @foo2 def f1(): return "Hello Andy" # f1 = foo2(f1) ==> print("d2") ==> f1 = inner2 # f1 = foo1(f1) ==> print("d1") ==> f1 = foo1(inner2) ==> inner1 ret = f1() # 调用f1() ==> inner1() ==> <i>inner2()</i> ==> <i><b>inner1()</b></i> ==> <i><b>Hello Andy</b></i> print(ret) 

带参数装饰器

被装饰的函数能够带参数,装饰器一样也能够带参数。函数

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

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

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

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

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

个人装饰器若是有参数的话,没地方写了…怎么办呢?it

仍是要使用闭包函数!io

咱们须要知道,函数除了能够嵌套两层,还能嵌套更多层:function

# 三层嵌套的函数1 def f1(): def f2(): name = "Andy" def f3(): print(name) return f3 return f2 

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

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

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

# 三层嵌套的函数2 def f1(): name = "Andy" def f2(): def f3(): print(name) return f3 return f2 

调用:

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

好了,如今咱们就能够实现咱们的带参数的装饰器函数了:

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

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

def d(a=None): # 定义一个外层函数,给装饰器传参数--role def foo(func): # foo是咱们原来的装饰器函数,func是被装饰的函数 def bar(*args, **kwargs): # args和kwargs是被装饰器函数的参数 # 根据装饰器的参数作一些逻辑判断 if a: print("欢迎来到{}页面。".format(a)) else: print("欢迎来到首页。") # 调用被装饰的函数,接收参数args和kwargs func(*args, **kwargs) return bar return foo @d() # 不给装饰器传参数,使用默认的'None'参数 def index(name): print("Hello {}.".format(name)) @d("电影") # 给装饰器传一个'电影'参数 def movie(name): print("Hello {}.".format(name)) if __name__ == '__main__': index("Andy") movie("Andy") 

输出:

欢迎来到首页。
Hello Andy.
欢迎来到电影页面。
Hello Andy.

类装饰器和装饰类

类装饰器

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

class D(object): def __init__(self, a=None): self.a = a self.mode = "装饰" def __call__(self, *args, **kwargs): if self.mode == "装饰": self.func = args[0] # 默认第一个参数是被装饰的函数 self.mode = "调用" return self # 当self.mode == "调用"时,执行下面的代码(也就是调用使用类装饰的函数时执行) if self.a: print("欢迎来到{}页面。".format(self.a)) else: print("欢迎来到首页。") self.func(*args, **kwargs) @D() def index(name): print("Hello {}.".format(name)) @D("电影") def movie(name): print("Hello {}.".format(name)) if __name__ == '__main__': index("Andy") movie("Andy") 

装饰类

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

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

# 定义一个类装饰器 class D(object): def __call__(self, cls): class Inner(cls): # 重写被装饰类的f方法 def f(self): print("Hello Andy.") return Inner @D() class C(object): # 被装饰的类 # 有一个实例方法 def f(self): print("Hello world.") if __name__ == '__main__': c = C() c.f() 
相关文章
相关标签/搜索