Python装饰器:如何在不改变已有函数的情况下增强函数功能
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编程中不可或缺的一部分。
