Python懒人必备:推荐7个高效实用的装饰器!

科技   2024-09-03 08:30   湖北  

【温馨提示】由于公众号更改了推送规则,不再按照时间顺序排列,如果不想错过测试开发技术精心准备的的干货文章,请将测试开发技术设为“星标☆”,看完文章在文尾处点亮“在看”!


对于编程新手来说,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(12))  # 输出 3,计算并缓存结果
print(example_function(12))  # 输出 3,从缓存中获取结果

也可以使用functools.lru_cache来实现缓存装饰器的效果

import functools

@functools.lru_cache(maxsize=None)
def example_function(x, y):
    return x + y

print(example_function(12))  # 输出 3,计算并缓存结果
print(example_function(12))  # 输出 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(12))  # 输出 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 时都会自动输出其性能分析结果。

如果觉得有用,就请关注点赞在看分享到朋友圈吧!


推荐阅读:

  1. 重磅发布!2024年全栈测试开发实战指南(第5期),技能进阶必备!

  2. 重磅消息 | 2023年最新全栈测试开发技能实战指南V2.0(第4期)

  3. 2024年,重磅发布!自动化测试全攻略,从入门到精通!

  4. 自动化测试全攻略:从入门到精通!

END

所有原创文章
第一时间发布至此公众号「测试开发技术」

长按二维码/微信扫码  添加作者

测试开发技术
专注于软件测试开发领域: 开源技术、工具/框架/平台、自动化测试、性能测试、安全测试、数据爬虫、Python、CI/CD、DevOps、职场成长分享。
 最新文章