装饰器是基于闭包的
什么是装饰器
装饰器是一个函数,主要作用是用来包装另一个函数或类
包装的目的是在不改变原函数名(或类名) 的情况下改变或添加被包装对象的行为
函数装饰器
是指装饰器是一个函数,传入的是一个函数,返回的也是一个函数
def mydeco(fn): def fx(): print("++++++++++++++++") print('----------------') return fx @mydeco def myfunc(): '''此函数将作为被装饰函数''' print("myfunc被调用") # myfunc上的@mydeco 等同于在 # 此处加上 myfunc=mydeco(myfunc) myfunc()
一 基于函数的装饰器
1.不带参数的装饰器
def debug(func): def wrapper(): print("[DEBUG]: enter {}()".format(func.__name__)) return func() return wrapper @debug def say_hello(): print("hello!")
2.带参数的装饰器
def debug(func): def wrapper(*args, **kwargs): # 指定宇宙无敌参数 print "[DEBUG]: enter {}()".format(func.__name__) print 'Prepare and say...', return func(*args, **kwargs) return wrapper # 返回 @debug def say(something): print "hello {}!".format(something)
def logging(level): def wrapper(func): def inner_wrapper(*args, **kwargs): print "[{level}]: enter function {func}()".format( level=level, func=func.__name__) return func(*args, **kwargs) return inner_wrapper return wrapper @logging(level='INFO') def say(something): print "say {}!".format(something) # 如果没有使用@语法,等同于 # say = logging(level='INFO')(say) @logging(level='DEBUG') def do(something): print "do {}...".format(something) if __name__ == '__main__': say('hello') do("my work")
https://www.cnblogs.com/cicaday/p/python-decorator.html
二 基于类的装饰器
1.不带参数的装饰器
装饰器函数其实是这样一个接口约束,它必须接受一个callable对象作为参数,然后返回一个callable对象。在Python中一般callable对象都是函数,但也有例外。只要某个对象重载了__call__()
方法,那么这个对象就是callable的
class Test(): def __call__(self): print 'call me!' t = Test() t() # call me
像__call__
这样前后都带下划线的方法在Python中被称为内置方法,有时候也被称为魔法方法。重载这些魔法方法一般会改变对象的内部行为。上面这个例子就让一个类对象拥有了被调用的行为。
回到装饰器上的概念上来,装饰器要求接受一个callable对象,并返回一个callable对象(不太严谨,详见后文)。那么用类来实现也是也可以的。我们可以让类的构造函数__init__()
接受一个函数,然后重载__call__()
并返回一个函数,也可以达到装饰器函数的效果。
class logging(object): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print "[DEBUG]: enter function {func}()".format( func=self.func.__name__) return self.func(*args, **kwargs) @logging def say(something): print "say {}!".format(something)
2带参数的类装饰器
如果需要通过类形式实现带参数的装饰器,那么会比前面的例子稍微复杂一点。那么在构造函数里接受的就不是一个函数,而是传入的参数。通过类把这些参数保存起来。然后在重载__call__
方法是就需要接受一个函数并返回一个函数。