什么是装饰器
# 概念:就是接受一个函数不改变里面的代码,进行包裹,然后返回函数的一个工具;不改变原函数调用方法的,对原函数进行包裹附加功能的工具
# 原理:利用高阶函数可以接受函数作为参数,返回函数作为结果实现迭代器
# 功能:极大的简化代码,避免编写重复性代码函数
# 本质:高阶函数
# @装饰器名字:等价于 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()