python基础-装饰器
什么是装饰器
# 概念:就是接受一个函数不改变里面的代码,进行包裹,然后返回函数的一个工具;不改变原函数调用方法的,对原函数进行包裹附加功能的工具 # 原理:利用高阶函数可以接受函数作为参数,返回函数作为结果实现迭代器 # 功能:极大的简化代码,避免编写重复性代码函数 # 本质:高阶函数 # @装饰器名字:等价于 f = decorate(f)。 # *args-**kw:要让 @log 自适应任何参数定义的函数,可以利用Python的 *args 和 **kw,保证任意个数的参数总是能正常调用。 # 打印日志:@log # 用户验证:@auth # 检测性能:@performance # 数据库事务:@transaction # URL路由:@post('/register')
无参数装饰器:就是没有参数的装饰器,一般两层包裹
# 无参数装饰器, # 由于decorator返回的新函数函数名已经不是'factorial',而是@log内部定义的'wrapper'。 # 这对于那些依赖函数名的代码就会失效。decorator还改变了函数的 __name__,__doc__等其它属性。 # 如果要让调用者看不出一个函数经过了@decorator的“改造”,就需要把原函数的一些属性复制到新函数中: # Python内置的functools可以用来自动化完成这个“复制”的任务: def log(f): def wrapper(*args,**kwargs): ret = f(*args,**kwargs) print("call "+f.__name__) return ret return wrapper @log def factorial(n): return reduce(lambda x,y:x*y,range(1,n+1)) result = factorial(3) print('result',result) f = log(factorial)(3) print('f',f) # 打印执行时间 import time def performance(f): def wrapper(*args,**kwargs): start = time.time() ret = f(*args,**kwargs) end = time.time() print('call %s() in %f'%(f.__name__,end-start)) return ret return wrapper @performance def factorial(n): return reduce(lambda x,y: x*y, range(1, n+1)) print(factorial(10))
有参装饰器:就是有参数的装饰器,一般三层包裹
# 有参数装饰器,三层函数 def log1(n): print(n*1000) def outer(f): def wrapper(*args,**kwargs): ret = f(*args,**kwargs) print("call "+f.__name__) return ret return wrapper return outer @log1(8) def factorial(n): return reduce(lambda x,y:x*y,range(1,n+1)) result = factorial(3) print(result) f = log1(8)(factorial)(3) print(f) # 内部返回函数名(参数),返回函数名,返回函数名 # 以下是返回的__name__ import time, functools # 没有加@functools.wraps(f): def performance(unit): def f(f): def wrapper(*args, **kwargs): t1 = time.time() ret = f(*args, **kwargs) t2 = time.time() if unit == 's': print("call %s() in %s" % (f.__name__, t2 - t1)) else: print("call %s() in %s" % (f.__name__, 1000 * (t2 - t1))) return ret return wrapper return f @performance('ms') def factorial(n): return reduce(lambda x, y: x * y, range(1, n + 1)) print("没有加@functools.wraps(f):",factorial.__name__) # 有加@functools.wraps(f): def performance(unit): def f(f): @functools.wraps(f) def wrapper(*args, **kwargs): t1 = time.time() ret = f(*args, **kwargs) t2 = time.time() if unit == 's': print("call %s() in %s" % (f.__name__, t2 - t1)) else: print("call %s() in %s" % (f.__name__, 1000 * (t2 - t1))) return ret return wrapper return f @performance('ms') def factorial(n): return reduce(lambda x, y: x * y, range(1, n + 1)) print("有加@functools.wraps(f):",factorial.__name__) # 就是在里面的函数外加个@functools.wraps(函数名的参数名)
如何使用两种:原函数和新装饰器函数
def outer(f): def wrapper(*args,**kwargs): ret=f(*args,**kwargs) print("hello2:",*args) return ret return wrapper @outer def foo(name): print("hello:",name) foo("adamanter") def wrapper(fn): def inner(): print("wrapped") fn() inner.raw = fn return inner @wrapper def foo(): print("go") if __name__ == '__main__': # 被装饰的 foo() print("--------") # 没被装饰的 foo.raw()