Python 中的修饰符(Decorator)是一种用于修改或扩展函数或类行为的工具。它们本质上是一个函数,接受另一个函数或类作为参数,并返回一个新的函数或类。修饰符通常用于在不修改原函数或类代码的情况下,添加额外的功能。
1. 基本概念
- 修饰符函数:一个接受函数或类作为参数,并返回新函数或类的函数。
- 语法糖:使用
@
符号简化修饰符的应用。
2. 函数修饰符
函数修饰符用于修改或扩展函数的行为。以下是一个简单的例子:
def my_decorator(func):def wrapper():print("Before function call")func()print("After function call")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()
输出:
Before function call
Hello!
After function call
my_decorator
是一个修饰符函数,接受func
作为参数。wrapper
是一个内部函数,用于包裹原函数func
,并在调用前后添加额外操作。@my_decorator
是语法糖,等同于say_hello = my_decorator(say_hello)
。
3. 带参数的函数修饰符
修饰符也可以接受参数,此时需要再嵌套一层函数:
def repeat(num_times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(num_times):result = func(*args, **kwargs)return resultreturn wrapperreturn decorator@repeat(3)
def greet(name):print(f"Hello {name}")greet("Alice")
输出:
Hello Alice
Hello Alice
Hello Alice
repeat
是一个带参数的修饰符函数,返回decorator
函数。decorator
接受func
作为参数,返回wrapper
函数。wrapper
包裹原函数func
,并根据num_times
参数重复调用。
4. 类修饰符
修饰符也可以用于类,修改或扩展类的行为:
def my_class_decorator(cls):class Wrapper:def __init__(self, *args, **kwargs):self.wrapped = cls(*args, **kwargs)def display(self):print("Before method call")self.wrapped.display()print("After method call")return Wrapper@my_class_decorator
class MyClass:def display(self):print("Displaying MyClass")obj = MyClass()
obj.display()
输出:
Before method call
Displaying MyClass
After method call
my_class_decorator
是一个类修饰符,接受cls
作为参数。Wrapper
是一个内部类,用于包裹原类cls
,并在方法调用前后添加额外操作。@my_class_decorator
是语法糖,等同于MyClass = my_class_decorator(MyClass)
。
5. 内置修饰符
Python 提供了一些内置修饰符,如 @staticmethod
、@classmethod
和 @property
:
@staticmethod
:将方法定义为静态方法,不接收self
或cls
参数。@classmethod
:将方法定义为类方法,第一个参数为cls
。@property
:将方法定义为属性,可以通过实例访问。
class MyClass:@staticmethoddef static_method():print("Static method")@classmethoddef class_method(cls):print(f"Class method of {cls}")@propertydef name(self):return self._name@name.setterdef name(self, value):self._name = valueMyClass.static_method()
MyClass.class_method()obj = MyClass()
obj.name = "Alice"
print(obj.name)
输出:
Static method
Class method of <class '__main__.MyClass'>
Alice
6. 修饰符的链式调用
多个修饰符可以链式调用,顺序从下往上执行:
def decorator1(func):def wrapper():print("Decorator 1")func()return wrapperdef decorator2(func):def wrapper():print("Decorator 2")func()return wrapper@decorator1
@decorator2
def say_hello():print("Hello!")say_hello()
输出:
Decorator 1
Decorator 2
Hello!
- 先应用
decorator2
,再应用decorator1
。
总结
Python 的修饰符是一种强大的工具,能够在不修改原函数或类代码的情况下,添加额外功能。它们广泛应用于日志记录、权限检查、性能测试等场景。理解修饰符的工作原理有助于编写更简洁、灵活的代码。