24、Python如何使用函数装饰器

装饰器是 Python 中的一种设计模式,用于在不修改函数或类的源代码的情况下,动态地增加或扩展其功能。装饰器本质上是一个高阶函数,它接收一个函数或类作为参数,并返回一个新的函数或类。

当我们想为多个函数,统一添加某种功能,比如计时统计、记录日志、缓存运算结果等等。代码封装有一个原则,就是同样的代码不要出现两遍,我们不想在每个函数内都添加完全相同的代码,这时就可以使用装饰器。

函数装饰器的基本用法

下面看一个斐波那契数列(Fibonacci Sequence)的案例,指的是这样一个数列:1,1,2,3,5,8,13,21, ... 。这个数列从第三项开始,每一项都等于前两项之和,求数列第n项。

# 典型的递归问题
def fibonacci(n):
    if n <= 1:
        return 1
    return fibonacci(n - 1) + fibonacci(n - 2)
# 打印的时候你会发现运行特别慢
# 原因是存在大量重复计算
# 当你算第50的时候,算了 49 和 48 的和
# 算49 的时候,又算了 48 和 47 的和
# 这里就重复算了48
# print(fibonacci(50))

# 这里有一个解决方案就是加缓存
# 我们这里单独定义一个函数,接收 fibonacci 的结果缓存起来
# 1.可以在很多地方通用,其他需要缓存的函数都可以用
# 2.如果是别人已经写好的函数,我们不想去改,防止出现未知问题
def cache_deco(func):
    cache = {}

    def wrap(*args):
        if args not in cache:
            cache[args] = func(*args)
        return cache[args]
    return wrap

# 这里我们还叫原来的名字,这样其他地方使用,还是使用同一个函数
fibonacci = cache_deco(fibonacci)
print(fibonacci(50))
# 这个运算结果就非常快了
# python提供了一个语法糖,也就是装饰器,@cache_deco
@cache_deco
def fibonacci2(n):
    if n <= 1:
        return 1
    return fibonacci(n - 1) + fibonacci(n - 2)
# 这里结果是一样的,这样就不需要写 fibonacci = cache_deco(fibonacci) 了
print(fibonacci2(50))

看上面的案例,相信大家已经知道函数装饰器的用法了,以及它存在的意义。

装饰器语法解释

装饰器的定义是以@符号开头来声明的,后面跟一个装饰器的名字decoratorName,decoratorName必须对应存在一个封闭函数,该封闭函数满足如下要求:

  • 参数是一个函数对象;
  • 封闭函数内部存在一个嵌套函数,该嵌套函数内会调用封闭函数参数指定的函数,并添加额外的其他代码(这些代码就是装饰);
  • 嵌套函数的参数必须包含originalFunction的参数,但不能带被装饰对象originalFunction;
  • 嵌套函数返回值必须与封闭函数参数指定函数的返回值类似,二者符合鸭子类型要求;
  • 封闭函数的返回值必须是嵌套函数。

多层装饰器

def decorator1(func):
    def wrap(*args, **kwargs):
        print("decorator1")
        return func(*args, **kwargs)
    return wrap

def decorator2(func):
    def wrap(*args, **kwargs):
        print("decorator2")
        return func(*args, **kwargs)
    return wrap

@decorator1
@decorator2
def my_func():
    print('my_func')

my_func()

# decorator1
# decorator2
# my_func

在上面的示例中,decorator1和decorator2是两个装饰器函数。my_func函数使用了两个装饰器,通过@语法将它们应用到my_func上。当调用my_func时,装饰器会按照从上到下的顺序依次执行。

你可能感兴趣的:(python)