@ 本质是语法糖- 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 仍然为类对象
上述装饰器实现有个问题,就是被装饰函数的属性被改变