【温馨提示】由于公众号更改了推送规则,不再按照时间顺序排列,如果不想错过测试开发技术精心准备的的干货文章,请将测试开发技术设为“星标☆”,看完文章在文尾处点亮“在看”!
对于编程新手来说,Python装饰器可能是一个稍显复杂的概念。简单来说,装饰器是一个函数,它可以接受另一个函数作为参数,并返回一个新的函数(通常是修改后的原始函数的版本)。这个特性使得装饰器在Python中成为一种非常强大且灵活的工具,可以用于在不修改原始函数代码的情况下,为其添加新的功能或修改其行为。常用于统计时间、插入日志、性能度量、权限校验、缓存、事务处理等场景。
想象一下,你有一个函数,它负责计算两个数的和。现在,你希望为这个函数添加一个计时功能,以便知道它执行需要多长时间。使用装饰器,你可以在不修改原始函数的情况下实现这一点。你只需编写一个装饰器函数,它接受原始函数作为参数,并返回一个新的函数,这个新函数在调用原始函数之前和之后分别记录时间,并计算执行时间。然后,你可以将这个装饰器应用到你的原始函数上,从而得到一个具有计时功能的新函数。
下述,列举几个常见装饰器的用法及示例,希望对大家有些许帮助。
1、计时装饰器
计时装饰器在Python中主要用于测量函数的执行时间,这在性能调优和代码优化时非常有用。例如,当你有一个复杂的算法或函数,你想知道它需要多长时间才能完成,或者你想比较两个不同实现的性能差异,你可以使用计时装饰器来测量它们的运行时间。
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__} 耗时: {end_time - start_time} 秒")
return result
return wrapper
@timer
def test_function():
time.sleep(3)
print("示例函数执行完毕")
test_function()
2、日志装饰器
日志装饰器的主要用途是在不修改原函数代码的情况下,为函数增加日志记录的功能。这样可以帮助开发者更好地了解程序的运行状态,跟踪错误以及分析性能问题。
import logging
def log_decorator(func):
def wrapper(*args, **kwargs):
logging.basicConfig(level=logging.INFO)
logging.info(f"开始执行 {func.__name__} 函数")
result = func(*args, **kwargs)
logging.info(f"{func.__name__} 函数执行完毕")
return result
return wrapper
@log_decorator
def example_function():
print("示例函数执行中...")
example_function()
3、缓存装饰器
缓存装饰器主要用于优化程序的性能,特别是在处理重复计算或I/O操作时。
import functools
def cache_decorator(func):
cache = dict()
@functools.wraps(func)
def wrapper(*args, **kwargs):
key = (args, tuple(kwargs.items()))
if key not in cache:
cache[key] = func(*args, **kwargs)
return cache[key]
return wrapper
@cache_decorator
def example_function(x, y):
return x + y
print(example_function(1, 2)) # 输出 3,计算并缓存结果
print(example_function(1, 2)) # 输出 3,从缓存中获取结果
也可以使用functools.lru_cache
来实现缓存装饰器的效果
import functools
@functools.lru_cache(maxsize=None)
def example_function(x, y):
return x + y
print(example_function(1, 2)) # 输出 3,计算并缓存结果
print(example_function(1, 2)) # 输出 3,从缓存中获取结果
functools.lru_cache
使用最近最少使用(LRU)策略来管理缓存的大小,这意味着它会保留最近使用的函数调用结果,而将长时间未使用的结果清除以释放内存空间。此外,lru_cache还提供了一些高级参数,如最大缓存大小、缓存过期时间等,使得开发者可以根据需求对缓存行为进行更细致的控制。
4、类型检查装饰器
类型检查装饰器在Python中主要用于确保函数调用时参数的数据类型与预期匹配,从而提高代码的健壮性和可维护性。
from functools import wraps
def type_check(func):
@wraps(func)
def wrapper(*args, **kwargs):
# 获取函数的参数注解
annotations = func.__annotations__
# 遍历参数和注解,检查类型是否正确
for arg, annotation in zip(args, annotations.values()):
if not isinstance(arg, annotation):
raise TypeError(f"参数 {arg} 的类型应为 {annotation},但实际类型为 {type(arg)}")
# 调用原始函数
return func(*args, **kwargs)
return wrapper
# 使用装饰器进行类型检查
@type_check
def add(a: int, b: int) -> int:
return a + b
print(add(1, 2)) # 输出 3
print(add("1", "2")) # 抛出 TypeError,因为参数类型不正确
5、单例装饰器
单例模式是一种设计模式,用于确保一个类只有一个实例,并提供一个全局访问点。在Python中,可以使用装饰器来实现单例模式。以下是一个简单的单例装饰器示例:
def singleton(cls):
instances = {}
def get_instance(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return get_instance
@singleton
class MyClass:
def __init__(self, x):
self.x = x
a = MyClass(1)
b = MyClass(2)
print(a is b) # 输出 True,说明 a 和 b 是同一个实例
6、重试装饰器
重试装饰器主要用于实现自动重试逻辑,以提高系统的稳定性和可靠性。以下是一个简单的重试装饰器示例:
import time
from functools import wraps
def retry(retries=3, delay=1):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for i in range(retries):
try:
return func(*args, **kwargs)
except Exception as e:
if i == retries - 1:
raise e
time.sleep(delay)
return wrapper
return decorator
@retry(retries=5, delay=2)
def my_function():
# 这里是你的函数实现
pass
在这个示例中,retry 装饰器接受两个参数:retries 表示最大重试次数,默认为3次;delay 表示每次重试之间的延迟时间,默认为1秒。当被装饰的函数抛出异常时,装饰器会自动重试指定次数,并在每次重试之间等待指定的延迟时间。如果达到最大重试次数仍然失败,则抛出最后一次捕获到的异常。
7、性能度量装饰器
cProfile是Python内置的性能分析工具,可以用于测量函数的执行时间和调用次数等信息。以下是使用cProfile来实现性能度量装饰器的示例:
import cProfile
from functools import wraps
def performance_metric(func):
@wraps(func)
def wrapper(*args, **kwargs):
profiler = cProfile.Profile()
profiler.enable()
result = func(*args, **kwargs)
profiler.disable()
profiler.print_stats()
return result
return wrapper
@performance_metric
def my_function():
# 这里是你的函数实现
pass
在这个示例中,我们首先导入了cProfile模块,并定义了一个名为performance_metric的装饰器。在装饰器内部,我们创建了一个cProfile.Profile对象,并启用它来开始性能分析。然后,我们调用原始函数并获取结果。最后,我们禁用性能分析器并打印出性能分析结果。
使用这个装饰器非常简单,只需要在需要测量性能的函数上方添加 @performance_metric 即可。例如,在上面的示例中,我们在 my_function 函数上使用了该装饰器,因此每次调用 my_function 时都会自动输出其性能分析结果。
如果觉得有用,就请关注、点赞、在看、分享到朋友圈吧!
推荐阅读:
END
所有原创文章
第一时间发布至此公众号「测试开发技术」
长按二维码/微信扫码 添加作者