1.装饰器:
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
正常的斐波拉函数:
def fibonacci(n):
if n <= 1:
return 1
return fibonacci(n - 1) + fibonacci(n - 2)
在求解的时候会存在大量的重复计算过程;f(8) = f(7)+f(6),f(7) = f(6)+f(5)
这里的f(6)存在一次重复计算,一次类推,在每个大于2的计算过程中都存在重复计算从而导致函数的开销很大,影响函数的效率;
我们在解决这个的问题的时候可以使用缓存:
def fibonacci(n,cache = None):
if cache is None:
cache = {}
if n in cache:
return cache[n]
if n <= 1:
return 1
cache[n] = fibonacci(n - 1,cache) + fibonacci(n - 2,cache)
return cache[n]
if __name__ == '__main__':
print(fibonacci(40))
这样定义了一个缓存,每次计算完毕都放到缓存字典中,每次计算先判断是否在缓存中,这样可以消除上面的重复计算的过程;但是在大量的这类问题面前,每个函数都要消除缓存的话,推荐装饰器
def memo(func):
cache = {}
def wrap(*args):
if args not in cache:
cache[args] = func(*args)
return cache[args]
return wrap
#装饰器的语法糖
@memo
def fibonacci(n):
if n <= 1:
return 1
return fibonacci(n - 1) + fibonacci(n - 2)
if __name__ == '__main__':
print(fibonacci(50))
2.如何为被装饰的函数保存元数据
在函数对象中保存着一些函数的元数据:
函数 | 描述 |
---|---|
f.____name__ | 函数的名字 |
f.____doc__ | 函数的文档字符串 |
f.____module__ | 函数所属模块名 |
f.____dict__ | 属性字典 |
f.____defaults__ | 默认参数元组 |
问题:我们在使用装饰器后,在使用上面这些属性访问时,看到的是内部包裹函数的元数据没原来函数的元数据丢丢失掉了,应该如何解决?
解决方案:使用标准库
functools
中的装饰器wraps
装饰内部包裹函数,可以制定将函数的某些属性,更新到包裹函数上面;