MST
星途 面试题库

面试题:Python装饰器嵌套中的元数据保留与复杂逻辑

有一个复杂的Python函数`complex_function`,它接受不定数量的位置参数和关键字参数,并且函数体中有循环和条件判断逻辑。编写三个装饰器:`cache_decorator`用于缓存函数结果(如果相同参数已经计算过,直接返回缓存结果),`error_handling_decorator`用于捕获函数执行过程中的特定异常并进行处理(比如`ZeroDivisionError`,捕获后返回一个特定值),`performance_monitor_decorator`用于监控函数执行的性能指标(例如函数执行时占用的内存峰值等,假设已有获取内存峰值的函数`get_memory_peak`可用)。要求以正确的顺序嵌套这三个装饰器,并确保函数的元数据(如函数名、文档字符串等)在装饰后依然保留,同时保证装饰器之间不会相互干扰其功能。请详细写出实现代码及必要的解释。
39.0万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
import functools
import tracemalloc


def cache_decorator(func):
    cache = {}

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        key = (args, tuple(sorted(kwargs.items())))
        if key in cache:
            return cache[key]
        result = func(*args, **kwargs)
        cache[key] = result
        return result

    return wrapper


def error_handling_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except ZeroDivisionError:
            return "捕获到除零错误,返回特定值"

    return wrapper


def performance_monitor_decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        tracemalloc.start()
        result = func(*args, **kwargs)
        current, peak = tracemalloc.get_traced_memory()
        tracemalloc.stop()
        print(f"函数 {func.__name__} 执行时占用的内存峰值: {peak} 字节")
        return result

    return wrapper


# 假设存在复杂函数
def complex_function(*args, **kwargs):
    """这是一个复杂函数的文档字符串"""
    # 这里是复杂的循环和条件判断逻辑示例
    total = 0
    for arg in args:
        if isinstance(arg, int):
            total += arg
    for value in kwargs.values():
        if isinstance(value, int):
            total += value
    return total


# 以正确顺序嵌套装饰器
complex_function = cache_decorator(error_handling_decorator(performance_monitor_decorator(complex_function)))


解释

  1. cache_decorator:
    • 使用字典cache来存储函数的计算结果。
    • functools.wraps用于保留原函数的元数据,如函数名和文档字符串。
    • 将位置参数args和关键字参数kwargs组成一个唯一的键key,如果keycache中,直接返回缓存的结果;否则,调用原函数计算结果并缓存。
  2. error_handling_decorator:
    • 使用try - except块捕获ZeroDivisionError异常。
    • functools.wraps保留原函数元数据。
    • 如果捕获到ZeroDivisionError,返回特定值;否则,正常返回原函数的执行结果。
  3. performance_monitor_decorator:
    • 使用tracemalloc模块来获取函数执行时占用的内存峰值。
    • functools.wraps保留原函数元数据。
    • 启动tracemalloc,调用原函数,获取当前内存和峰值内存,停止tracemalloc,并打印内存峰值,最后返回原函数执行结果。
  4. 装饰器嵌套顺序
    • 这里将cache_decorator放在最外层,error_handling_decorator在中间,performance_monitor_decorator在最内层。这样的顺序确保了先进行性能监控,然后处理异常,最后缓存结果,且各装饰器功能互不干扰。同时,functools.wraps保证了原函数的元数据在装饰后依然保留。