欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

深入分析 Python 装饰器:从基础到高级应用,掌握增强代码功能的强大工具-3。高级装饰器

最编程 2024-06-10 13:47:12
...

装饰器不仅限于无参数的函数,它们也可以装饰接收参数的函数。此外,装饰器本身也可以接收参数。

3.1 装饰带参数的函数

当装饰的函数需要接收参数时,需要在内部wrapper函数中正确处理这些参数

def trace(func):
    def wrapper(*args, **kwargs):
        print(f"Calling {func.__name__} with args {args} and kwargs {kwargs}")
        result = func(*args, **kwargs)
        print(f"{func.__name__} returned {result}")
        return result
    return wrapper

@trace
def calculate_area(length, width):
    return length * width

area = calculate_area(10, 20)
print(f"Area: {area}")
# Calling calculate_area with args (10, 20) and kwargs {}
# calculate_area returned 200
# Area: 200

trace装饰器被定义为监控任何函数的调用和返回值。装饰器内部的wrapper函数记录了传递给calculate_area函数的参数(lengthwidth)以及该函数的返回结果(计算的面积)。

装饰器接收函数参数的方式不限于使用 *args 和 **kwargs,这只是一种通用的方法而已,可以使得装饰器能够适用于任意参数的函数。

3.2 带参数的装饰器

有时我们希望装饰器本身能够接收参数。创建一个带参数的装饰器,该装饰器允许指定函数被调用的次数。

def repeat(num_times):
    """装饰器工厂,接收一个参数指定函数重复执行的次数。"""
    def decorator_repeat(func):
        """实际的装饰器,用于包装函数,使其可以重复执行指定次数。"""
        def wrapper(*args, **kwargs):
            """包装函数,执行被装饰函数多次,并在最后一次保留返回结果。"""
            result = None
            for _ in range(num_times):
                result = func(*args, **kwargs)
            return result
        return wrapper
    return decorator_repeat

@repeat(num_times=2)
def greet(name):
    """一个简单的问候函数,打印问候语并不返回任何值。"""
    print(f"Hello, {name}!")

greet("Alice")
# Hello, Alice!
# Hello, Alice!
  1. 装饰器工厂repeat函数接收一个参数num_times,这个参数指定了被装饰的函数需要重复执行的次数。这使得repeat不仅仅是一个装饰器,而是一个装饰器工厂,它根据传入的参数创建并返回一个具体的装饰器。
  2. 实际的装饰器decorator_repeat是在repeat函数内部定义的函数,是真正的装饰器。它的任务是接收一个函数并返回一个包装过的版本。
  3. 包装函数wrapper函数是在decorator_repeat内部定义的。这个函数负责实际调用原始函数(在本例中为greet函数),并根据num_times的值重复执行它。

补充:

解释一下for _ in range(num_times):中的_

**_**是一个常用于循环中的占位符。当在循环中不需要使用到循环变量时,可以使用下划线(_)作为一个临时或者“不关心”的变量名。这是一个惯用法,表示循环次数的变量在循环体中没有被实际用到。

推荐阅读