Python 中的装饰器如何工作?

装饰器(Decorator)是 Python 中一种高级特性,它允许程序员修改或增强函数和方法的行为,而无需直接更改其源代码。装饰器本质上是一个返回函数的高阶函数,它可以接收一个函数作为参数,并返回一个新的或修改后的函数。通过使用装饰器,您可以实现诸如日志记录、访问控制、性能测量等功能,同时保持代码的清晰和模块化。
装饰器的工作原理装饰器定义:首先,您需要定义一个装饰器函数。这个函数接受一个被装饰的函数作为参数,并返回一个新的函数(通常是内部定义的一个闭包),该新函数可以在执行原始函数之前或之后添加额外逻辑。

应用装饰器:要将装饰器应用于某个函数,可以使用 @decorator_name 语法糖,放在函数定义之前。这相当于在函数定义后立即调用装饰器并将函数作为参数传递给它。

执行流程:当调用被装饰的函数时,实际上是在调用装饰器返回的新函数。这意味着您可以在实际执行目标函数之前或之后插入自定义行为。

示例:基本装饰器

def my_decorator(func):    def wrapper():        print("Something is happening before the function is called.")        func()        print("Something is happening after the function is called.")    return wrapper@my_decoratordef say_hello():    print("Hello!")say_hello()# 输出:# Something is happening before the function is called.# Hello!# Something is happening after the function is called.

在这个例子中,my_decorator 是一个简单的装饰器,它包装了 say_hello 函数,在调用前后打印消息。

带参数的装饰器

有时,您可能希望装饰器本身也能接受参数。为了实现这一点,可以创建一个“装饰器工厂”——即一个返回装饰器的函数。示例:带参数的装饰器

def repeat(num_times):    def decorator_repeat(func):        def wrapper(*args, **kwargs):            for _ in range(num_times):                result = func(*args, **kwargs)            return result        return wrapper    return decorator_repeat@repeat(num_times=3)def greet(name):    print(f"Hello {name}")greet("Alice")# 输出:# Hello Alice# Hello Alice# Hello Alice

这里,repeat 是一个装饰器工厂,它根据提供的 num_times 参数生成一个具体的装饰器。

类装饰器

除了函数,Python 还支持类装饰器。类装饰器通常用于修改类的行为或属性。它们接收类作为参数,并返回一个新的类或修改后的类。示例:类装饰器

def add_method(cls):    def decorator(func):        setattr(cls, func.__name__, func)        return cls    return decorator@add_methodclass MyClass:    pass@add_method(MyClass)def new_method(self):    print("This is a dynamically added method.")obj = MyClass()obj.new_method()  # 输出: This is a dynamically added method.

在这个例子中,add_method 是一个类装饰器,它向 MyClass 动态添加了一个新的方法。

内置装饰器Python 提供了一些内置的装饰器来简化常见的编程任务:

@classmethod 和 @staticmethod:用于定义类方法和静态方法。

@property:用于将类的方法转换为只读属性。

@functools.lru_cache:用于缓存函数的结果以提高性能。

@dataclasses.dataclass:用于自动为类生成特殊方法(如 __init__() 和 __repr__())。

示例:使用 @property

class Circle:    def __init__(self, radius):        self._radius = radius    @property    def radius(self):        """The radius property."""        print("Getting radius")        return self._radius    @radius.setter    def radius(self, value):        if value >= 0:            self._radius = value        else:            raise ValueError("Radius must be non-negative")circle = Circle(5)print(circle.radius)  # 输出: Getting radius\n5circle.radius = 10print(circle.radius)  # 输出: Getting radius\n10

使用多个装饰器

如果一个函数被多个装饰器修饰,则这些装饰器按照从下到上的顺序依次应用。也就是说,最接近函数定义的装饰器最先执行。示例:多个装饰器

def decorator_one(func):    def wrapper():        print("Decorator one")        func()    return wrapperdef decorator_two(func):    def wrapper():        print("Decorator two")        func()    return wrapper@decorator_one@decorator_twodef hello():    print("Hello!")hello()# 输出:# Decorator one# Decorator two# Hello!

在这个例子中,decorator_two 首先被应用,然后是 decorator_one。

总结装饰器是 Python 中非常强大且灵活的工具,它们可以让您以优雅的方式扩展或修改函数和类的功能。通过理解装饰器的工作原理以及如何构建自己的装饰器,您可以编写出更加简洁、可维护和功能丰富的代码。随着经验的积累,您还将发现更多关于装饰器的高级用法和最佳实践。

THE END