Python装饰器函数详解及实例
Python装饰器是Python语言中一个重要的概念,它是在函数运行时动态地修改函数的行为。Python装饰器允许我们在不修改函数的情况下扩展或修改函数的行为。这篇文章将详细介绍Python装饰器的定义、作用、分类、使用方法、实例等方面的知识。
一、装饰器函数的概念
装饰器函数是Python语法的一个特性。它是用来修改或者包装函数的函数。装饰器函数是高阶函数的一种,它接收一个函数作为参数并返回一个被修改后的函数。这种做法在Python中被广泛应用,特别是在web框架和数据库ORM框架中经常见到。
二、装饰器函数的作用
Python装饰器提供了一种统一且优美的方式,可以在不改变函数本身的情况下扩展或者修改函数的行为。
装饰器函数可以用来增强函数的功能,比如计时,缓存,权限认证,参数校验等。
装饰器函数也可以用来给函数增加一些元信息(比如函数名、文档字符串),这有助于提高代码的可读性和可维护性。
三、装饰器函数的分类
根据装饰器是否需要参数,可以将装饰器分为有参装饰器和无参装饰器。
1. 无参装饰器
无参装饰器是最简单的装饰器。它不需要传递任何参数,只需要在函数定义前使用@符号来调用即可。
例如,下面的代码演示了一个简单的无参装饰器,用来计算函数运行时间:
import time
def timeit(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(f'函数{func.__name__}的运行时间为{end_time-start_time}秒')
return res
return wrapper
@timeit
def foo():
time.sleep(3)
foo()
输出结果:
函数foo的运行时间为3.0035061836242676秒
2. 有参装饰器
有参装饰器和无参装饰器的区别就在于有参装饰器需要传递参数。有参装饰器可以用来执行额外的任务,比如设置缓存时间。
例如,下面的代码演示了一个简单的有参装饰器,用来设置函数缓存时间:
import functools
def cache(duration):
def dec(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
now_time = time.time()
if key in wrapper.cache:
if now_time - wrapper.cache[key]['time'] > duration:
print(f'缓存超时,更新缓存{key}')
wrapper.cache.pop(key)
res = func(*args, **kwargs)
wrapper.cache[key] = {'data': res, 'time': now_time}
else:
print(f'从缓存中获取{key}')
res = wrapper.cache[key]['data']
else:
print(f' 次执行{key},写入缓存')
res = func(*args, **kwargs)
wrapper.cache[key] = {'data': res, 'time': now_time}
return res
wrapper.cache = {}
return wrapper
return dec
@cache(duration=3)
def bar(a, b):
time.sleep(2)
return a + b
print(bar(1, 2))
print(bar(1, 2))
输出结果:
次执行(1, 2){},写入缓存
3
从缓存中获取(1, 2){}
3
四、装饰器函数的使用方法
Python装饰器的使用方法非常简单,只需要在函数定义前添加@装饰器函数名即可。
例如,下面的代码演示了如何使用装饰器函数来扩展函数功能:
import time
def timeit(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(f'函数{func.__name__}的运行时间为{end_time-start_time}秒')
return res
return wrapper
@timeit
def foo():
time.sleep(3)
foo()
输出结果:
函数foo的运行时间为3.0035061836242676秒
五、装饰器函数的实例
1. 计时装饰器
下面的代码演示了如何使用装饰器函数来计算函数的运行时间:
import time
def timeit(func):
def wrapper(*args, **kwargs):
start_time = time.time()
res = func(*args, **kwargs)
end_time = time.time()
print(f'函数{func.__name__}的运行时间为{end_time-start_time}秒')
return res
return wrapper
@timeit
def foo():
time.sleep(3)
foo()
输出结果:
函数foo的运行时间为3.0035061836242676秒
2. 缓存装饰器
下面的代码演示了如何使用装饰器函数来缓存函数的运算结果:
import functools
def cache(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = str(args) + str(kwargs)
if key in wrapper.cache:
print(f'从缓存中获取{key}')
return wrapper.cache[key]
else:
print(f' 次执行{key},写入缓存')
res = func(*args, **kwargs)
wrapper.cache[key] = res
return res
wrapper.cache = {}
return wrapper
@cache
def bar(a, b):
time.sleep(3)
return a + b
print(bar(1, 2))
print(bar(1, 2))
输出结果:
次执行(1, 2){},写入缓存
3
从缓存中获取(1, 2){}
3
3. 权限认证装饰器
下面的代码演示了如何使用装饰器函数来进行权限认证:
def login_required(func):
def wrapper(request, *args, **kwargs):
if request.get('user'):
return func(request, *args, **kwargs)
else:
return '请先登录'
return wrapper
@login_required
def user_page(request):
return f'欢迎您,{request.get("user")}'
print(user_page({'user': 'Tom'}))
print(user_page({'admin': 'Tom'}))
输出结果:
欢迎您,Tom
请先登录
4. 参数校验装饰器
下面的代码演示了如何使用装饰器函数来进行参数校验:
def check_args(func):
def wrapper(*args, **kwargs):
if not all(isinstance(arg, int) for arg in args):
return '参数类型错误'
if 'page' in kwargs and not isinstance(kwargs['page'], int):
return 'page参数类型错误'
return func(*args, **kwargs)
return wrapper
@check_args
def get_data(a, b, page=None):
return [i for i in range(a, b+1)][page*10-10:page*10] if page else [i for i in range(a, b+1)]
print(get_data(2, 100))
print(get_data('a', 'b'))
print(get_data(2, 100, page=1))
print(get_data(2, 100, page='a'))
输出结果:
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
参数类型错误
[
