@ 本質是語法糖- Syntactic Sugar
使用@decorator 來修飾某個函數 func 時:python
@decorator def func(): pass
其解釋器會解釋成:數組
func = decorator(func)
注意這條語句會被執行app
多重裝飾器ide
@decorator_one @decorator_two def func(): pass
至關於:函數
func = decorator_one(decorator_two(func))
帶參數裝飾器url
@decorator(arg1, arg2) def func(): pass
至關於:code
func = decorator(arg1,arg2)(func)
*args、**kwargs
給被裝飾函數傳遞參數def wrapper(func): def wrapper_in(*args, **kwargs): # args是一個數組,kwargs一個字典 print("%s is running" % func.__name__) return func(*args, **kwargs) return wrapper_in @wrapper def func(parameter1, parameter2, key1=1): print("call func with {} {} {}".format(parameter1, parameter2, key1)) func("haha", None, key1=2) # func is running # call func with haha None 2
def log(level): def decorator(func): def wrapper(*args, **kwargs): if level == "warn": print("%s with warn is running" % func.__name__) elif level == "info": print("%s with info is running" % func.__name__) return func(*args, **kwargs) return wrapper return decorator @log("warn") def foo(*args, **kwargs): print("args {}, kwargs{}".format(args, kwargs)) foo(1, 2, a = 3) # foo with warn is running # args (1, 2), kwargs{'a': 3}
等同於orm
def foo(name='foo'): print("args {}, kwargs{}".format(args, kwargs)) foo = log("warn")(foo)
類方法是一個特殊的函數,它的第一個參數 self 指向類實例
因此咱們一樣能夠裝飾類方法對象
def decorate(func): def wrapper(self): return "<p>{0}</p>".format(func(self)) return wrapper class Person(object): def __init__(self): self.name = "John" self.family = "Doe" @decorate def get_fullname(self): return self.name+" "+self.family my_person = Person() print my_person.get_fullname() # <p>John Doe</p>
上例至關於固定了 self 參數,不太靈活
使用 *args, **kwargs
傳遞給 wrapper 更加通用:路由
def pecorate(func): def wrapper(*args, **kwargs): return "<p>{0}</p>".format(func(*args, **kwargs)) return wrapper class Person(object): def __init__(self): self.name = "John" self.family = "Doe" @pecorate def get_fullname(self): return self.name+" "+self.family my_person = Person() print my_person.get_fullname()
類實現 __call__
方法後變成可調用對象,故能夠用類作裝飾器
class EntryExit(object): def __init__(self, f): self.f = f def __call__(self): print "Entering", self.f.__name__ self.f() print "Exited", self.f.__name__ @EntryExit def func1(): print "inside func1()" @EntryExit def func2(): print "inside func2()" def func3(): pass print type(EntryExit(None)) # func1 變爲類實例 print type(func1) print type(EntryExit) # func3 是普通函數 print type(func3) func1() func2() # <class '__main__.EntryExit'> # <class '__main__.EntryExit'> # <type 'type'> # <type 'function'> # Entering func1 # inside func1() # Exited func1 # Entering func2 # inside func2() # Exited func2
類裝飾器
@EntryExit def func1(): print "inside func1()"
等同於
def func1(): print "inside func1()" # 此處能夠看出 func1 是類EntryExit的一個實例 func1 = EntryExit(myfunc1)
register_handles = [] def route(url): global register_handles def register(handler): register_handles.append((".*$", [(url, handler)])) return handler return register @route("/index") class Index(): def get(self, *args, **kwargs): print("hi") # Index 仍然爲原來定義的類實例 # 至關於在定義類的同時調用裝飾器函數 route, 將該類註冊到全局路由 register_handles @route("/main") class Main(): def get(self, *args, **kwargs): print("hi") print (register_handles) print(type(Index)) # [('.*$', [('/index', <class __main__.Index at 0x0000000002A49828>)]), ('.*$', [('/main', <class __main__.Main at 0x0000000002FBABE8>)])] # <type 'classobj'>
@route("/index") class Index(): def get(self, *args, **kwargs): print("hi")
Index = route("/index")(Index) # register 返回傳入的 handler,故 Index 仍然爲類對象
上述裝飾器實現有個問題,就是被裝飾函數的屬性被改變