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
def 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
def greet(name):
print(f"Hello {name}")
greet("Alice")
# 输出:
# Hello Alice
# Hello Alice
# Hello Alice
这里,repeat 是一个装饰器工厂,它根据提供的 num_times 参数生成一个具体的装饰器。
类装饰器
def add_method(cls):
def decorator(func):
setattr(cls, func.__name__, func)
return cls
return decorator
class MyClass:
pass
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 动态添加了一个新的方法。
@classmethod 和 @staticmethod:用于定义类方法和静态方法。
@property:用于将类的方法转换为只读属性。
@functools.lru_cache:用于缓存函数的结果以提高性能。
@dataclasses.dataclass:用于自动为类生成特殊方法(如 __init__() 和 __repr__())。
示例:使用 @property
class Circle:
def __init__(self, radius):
self._radius = radius
def radius(self):
"""The radius property."""
print("Getting radius")
return self._radius
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\n5
circle.radius = 10
print(circle.radius) # 输出: Getting radius\n10
使用多个装饰器
def decorator_one(func):
def wrapper():
print("Decorator one")
func()
return wrapper
def decorator_two(func):
def wrapper():
print("Decorator two")
func()
return wrapper
def hello():
print("Hello!")
hello()
# 输出:
# Decorator one
# Decorator two
# Hello!
在这个例子中,decorator_two 首先被应用,然后是 decorator_one。
THE END