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

Python装饰器:如何在不改变已有函数的情况下增强函数功能

发布时间:2023-06-12 21:56:39

Python装饰器是一种很有用的技术,它可以在不改变已有函数的情况下增强函数的功能。具体来说,装饰器可以在不修改函数代码的情况下,给函数添加一些额外的功能或行为,比如计时、日志、缓存、权限验证等等,这样可以让代码更加模块化、可维护和可重用。

在Python中,装饰器就是一个函数,可以接收一个函数作为参数,并返回一个新的函数。装饰器的主要作用就是把被装饰的函数替换成新的函数,从而实现增强功能的目的。

下面我们来一个一个地讲解如何使用装饰器增强函数的功能。

1.计时

计时是一种很常见的需求,我们可以使用装饰器来实现对函数执行时间的统计。下面是一个计时的装饰器函数:

import time

def timer(func):
    def wrapper(*args, **kwargs):
        start_time = time.time()
        result = func(*args, **kwargs)
        end_time = time.time()
        print(f'{func.__name__} cost {end_time - start_time:.4f} seconds')
        return result
    return wrapper

这个装饰器函数接收一个函数作为参数,返回一个新的函数wrapper。wrapper函数中,首先记录当前时间作为函数执行开始的时间,然后执行被装饰的函数func,并记录函数执行结束的时间。最后,输出函数执行时间,并返回函数结果。

我们可以将@timer放在需要计时的函数上面,比如:

@timer
def test():
    time.sleep(1)
    return 'test'

test()

这样就可以输出函数执行时间了。

2.日志

日志是一种很重要的功能,可以帮助我们更好地理解程序运行过程中的问题。我们可以使用装饰器来给函数添加日志功能,记录函数执行时的输入和输出。

下面是一个记录日志的装饰器函数:

def logger(func):
    def wrapper(*args, **kwargs):
        result = func(*args, **kwargs)
        print(
            f'{func.__name__}('
            f'{", ".join(str(arg) for arg in args)}, '
            f'{", ".join(f"{k}={v}" for k, v in kwargs.items())}) '
            f'-> {result}'
        )
        return result
    return wrapper

这个装饰器函数同样接收一个函数作为参数,返回一个新的函数wrapper。wrapper函数中,首先执行函数func,并记录函数的返回值result。然后,输出函数的输入参数和输出结果,并返回函数结果。

我们可以将@logger放在需要记录日志的函数上面,比如:

@logger
def add(a, b):
    return a + b

add(1, 2)

这样就可以输出函数输入和输出了。

3.缓存

缓存是一种可以显著提高程序性能的技术,可以帮助我们避免重复计算,提高程序效率。我们可以使用装饰器来实现函数的缓存功能,将函数调用的结果保存下来,避免重复计算。

下面是一个实现函数缓存的装饰器函数:

def cache(func):
    cache_dict = {}
    def wrapper(*args):
        if args in cache_dict:
            return cache_dict[args]
        else:
            result = func(*args)
            cache_dict[args] = result
            return result
    return wrapper

这个装饰器函数同样接收一个函数作为参数,返回一个新的函数wrapper。wrapper函数中,首先检查函数是否已被缓存,如果已经被缓存,则直接返回缓存的结果;否则,执行函数并缓存执行结果,并返回函数结果。

我们可以将@cache放在需要缓存的函数上面,比如:

@cache
def factorial(n):
    if n == 1:
        return 1
    else:
        return n * factorial(n-1)

print(factorial(10))

这样就可以实现对函数调用结果的缓存了。

4.权限验证

权限验证是一种很常见的需求,可以帮助我们保护系统的安全和隐私。我们可以使用装饰器给函数添加权限验证功能,确保只有具有特定权限的用户可以执行该函数。

下面是一个实现权限验证的装饰器函数:

def check_permission(permissions):
    def decorator(func):
        def wrapper(*args, **kwargs):
            user = kwargs.pop('user')
            if set(permissions).issubset(user.permissions):
                return func(*args, **kwargs)
            else:
                raise PermissionDenied
        return wrapper
    return decorator

这个装饰器函数实际上是一个嵌套的函数。 层函数接收一个参数permissions,返回一个新的函数decorator;第二层函数接收一个函数作为参数,返回一个新的函数wrapper。wrapper函数中,首先取出参数user,检查用户是否具有指定的权限,如果有,则执行函数func;否则,抛出权限错误异常。

我们可以将@check_permission放在需要权限验证的函数上面,比如:

class User:
    def __init__(self, name, permissions):
        self.name = name
        self.permissions = permissions

def get_user(id):
    return User('Alice', {'read', 'write'})

@check_permission({'read'})
def view_document(id, user):
    return f'Document {id} can be read by {user.name}'

user = get_user(1)
print(view_document(1, user=user))

这样就可以确保只有具有read权限的用户可以查看文档了。

综上所述,Python装饰器可以在不改变已有函数的情况下增强函数功能,可以在函数执行前、执行后以及执行过程中加入额外的功能或行为,比如计时、日志、缓存、权限验证等等。使用装饰器可以让代码更加模块化、可维护和可重用,是Python编程中不可或缺的一部分。