欢迎访问宙启技术站
智能推送

Python函数中的装饰器实现

发布时间:2023-06-06 16:01:58

Python 函数中的装饰器是一种在运行时动态增加函数功能的方式,它可以在不修改原函数代码的情况下,给函数附加一些额外的功能。装饰器本质上是一个函数,它可以接受一个函数作为参数,并返回一个新的函数。在调用原函数之前或之后,装饰器可以执行一些额外的逻辑,比如打印日志、记录执行时间、缓存结果等。

为了更好地理解 Python 函数中的装饰器,我们可以通过一个示例来演示它的用法。假设我们有一个简单的函数,它接受两个参数,计算它们的和并返回结果,代码如下:

def add(x, y):
    return x + y

现在我们想要给这个函数增加一个日志记录功能,每次调用函数时都将计算的结果记录下来。我们可以使用装饰器来实现这个功能,代码如下:

def log(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(f"Call {func.__name__}{args} -> {result}")
        return result
    return wrapper

@log
def add(x, y):
    return x + y

在这个实现中,我们定义了一个 log 函数作为装饰器,它接受一个函数作为参数,并返回一个新的包装函数 wrapper。在包装函数中,我们首先调用原函数得到结果,然后打印日志并返回结果。最后,我们使用 @log 语法糖将 add 函数应用装饰器。

现在,每次我们调用 add 函数时,都会自动打印出计算结果,比如下面的示例:

>>> add(1, 2)
Call add(1, 2) -> 3
3

>>> add(3, 4)
Call add(3, 4) -> 7
7

在这个示例中,装饰器 log 可以通过包装函数 wrapper 实现对 add 函数的增强。当我们调用 add 函数时,实际上是在调用 wrapper 函数。由于 wrapper 函数已经被装饰器 log 修饰过,它会在调用 add 函数之前和之后打印日志,然后返回结果。

装饰器可以被用来实现各种功能,比如缓存、授权、限制访问频率等。下面是一些常见的装饰器实现。

1. 缓存装饰器

缓存装饰器可以用来缓存函数的结果,避免重复计算。它基于一个缓存字典,每次调用函数时,先检查缓存字典中是否已经存在计算结果,如果存在则直接返回,否则执行函数并将结果加入缓存字典。代码如下:

import functools

def cache(func):
    memo = {}

    @functools.wraps(func)
    def wrapper(*args):
        if args in memo:
            return memo[args]
        else:
            result = func(*args)
            memo[args] = result
            return result

    return wrapper

在这个实现中,我们定义了一个 memo 字典作为缓存,每次调用缓存装饰器时,都会创建一个新的 memo 字典。在包装函数 wrapper 中,我们先检查缓存字典中是否已经存在计算结果,如果存在则直接返回,否则执行函数并将结果加入缓存字典。

2. 授权装饰器

授权装饰器可以用来限制用户访问函数的权限。它基于一个用户令牌字典,每次调用函数时,需要检查用户是否拥有访问函数的权限。如果用户没有权限,则返回一个错误信息。代码如下:

import functools

def authorize(permission):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            token = kwargs.get("token")
            if token and token in permission:
                return func(*args, **kwargs)
            else:
                return "Access Denied"
        return wrapper
    return decorator

在这个实现中,我们定义了一个 authorize 函数作为装饰器工厂,它接受一个参数 permission,表示具有访问函数权限的用户令牌。在 authorize 函数内部,我们定义了一个 decorator 函数,它接受一个函数作为参数,并返回一个包装函数 wrapper。在 wrapper 函数中,我们检查 kwargs 参数中是否存在 token 字段,并检查该令牌是否在 permission 列表中。如果用户具有访问权限,则调用原函数并返回结果,否则返回一个错误信息。

3. 记录执行时间装饰器

记录执行时间装饰器可以用来记录函数的执行时间,方便优化代码性能。它使用 time 模块来计算函数的执行时间。代码如下:

import time
import functools

def timed(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"Executed {func.__name__} in {end - start} seconds")
        return result
    return wrapper

在这个实现中,我们定义了一个 timed 装饰器,它使用 time 模块来计算函数的执行时间。在包装函数 wrapper 中,我们记录函数执行的起始和结束时间,并计算二者之差,最后打印出执行时间。

以上是 Python 函数中的装饰器实现的一些示例。装饰器是 Python 中非常有用的特性,可以帮助我们实现多种功能,提高代码灵活性和可重用性。了解装饰器的实现方式,也有助于我们更好地理解 Python 的语法和内部机制。