跳转至

装饰器(Decorators)

装饰器是 Python 中的一种高级功能,用于动态地修改函数或类的行为。

装饰器实际上是一种函数,它接受一个函数作为参数,并返回一个新的函数或修改原来的函数。

装饰器1
装饰器的工作原理示意图

装饰器的语法为 @decorator_name ,写在函数或方法前。

Python 还提供了一些内置的装饰器,如 @staticmethod 和 @classmethod 用于定义静态方法和类方法。

基本语法

def deco(func):
    def wrapper():
        print("在原函数之前执行")
        func()
        print("在原函数之后执行")
    return wrapper

@deco
def hello():
    print("Hello!")

hello()
Output
1
2
3
在原函数之前执行
Hello!
在原函数之后执行

  • deco 是一个装饰器函数,它接受 hello 函数作为参数,并返回 wrapper 函数。
  • @decohello 替换为 wrapper 函数。
  • 使用装饰器后再调用 hello() 等价于 deco(hello)()

带参数的装饰器

分两种情况。

原函数带参数

def deco(func):  
    def wrapper(*args, **kwargs):  
        print("在原函数之前执行")  
        func(*args, **kwargs)  
        print("在原函数之后执行")  
    return wrapper  

@deco  
def greet(s1, s2):  
    print(s1, s2)  

greet("Hello", "World")
Output
1
2
3
在原函数之前执行
Hello World
在原函数之后执行

这里 wrapper 函数的参数用 (*args, **kwargs) 来保持对不同函数的通用性。

装饰器函数带参数

def repeat(times):  
    def deco(func):  
        def wrapper(*args, **kwargs):  
            for _ in range(times):  
                func(*args, **kwargs)  
        return wrapper  
    return deco  

@repeat(3)  
def greet(s1, s2):  
    print(s1, s2)  

greet("Hello", "World")
Output
1
2
3
Hello World
Hello World
Hello World

repeat 函数是一个**装饰器工厂**,它接受一个参数 times,返回一个装饰器 decorator (这就是多出来的一层函数)。

decorator 接受一个函数 func,并返回一个 wrapper 函数。

wrapper 函数会调用 func 函数 times 次。

使用 @repeat(3) 装饰 greet 函数后,调用 greet 会打印三次。

类装饰器

除了函数装饰器,Python 还支持类装饰器。类装饰器是包含 call 方法(每次调用装饰后函数时的行为)的类,它接受一个函数作为参数,并返回一个新的函数。

def my_decorator(cls):
    class Wrapper:
        def __init__(self, *args, **kwargs):
            self.wrapped = cls(*args, **kwargs)

        def display(self):
            print("在类方法之前执行")
            self.wrapped.display()
            print("在类方法之后执行")
    return Wrapper

@my_decorator
class MyClass:
    def display(self):
        print("这是 MyClass 的 display 方法")

obj = MyClass()
obj.display()
Output
1
2
3
在类方法之前执行
这是 MyClass 的 display 方法
在类方法之后执行

内置装饰器

Python 提供了一些内置的装饰器,例如:

  1. @staticmethod: 将方法定义为静态方法,不需要实例化类即可调用。

  2. @classmethod: 将方法定义为类方法,第一个参数是类本身(通常命名为 cls)。

  3. @property: 将方法转换为属性,使其可以像属性一样访问。

实例:

class MyClass:
    @staticmethod
    def static_method():
        print("This is a static method.")

    @classmethod  
    def class_method(cls):  
        print(f"This is a class method of {cls.__name__}.")  

    @property  
    def name(self):  
        return self._name  

    @name.setter  
    def name(self, value):  
        self._name = value  

# 使用  
MyClass.static_method()  
MyClass.class_method()  

obj = MyClass()  
obj.name = "Alice"  
print(obj.name)  

多个装饰器的堆叠

你可以将多个装饰器堆叠在一起,它们会按照从下到上的顺序依次应用。

实例:

def decorator1(func):
    def wrapper():
        print("Decorator 1")
        func()
    return wrapper

def decorator2(func):
    def wrapper():
        print("Decorator 2")
        func()
    return wrapper

@decorator1
@decorator2
def say_hello():
    print("Hello!")

say_hello()
Output
1
2
3
Decorator 1
Decorator 2
Hello!