装饰器(Decorator)是一种用于修改函数或方法行为的函数,通常用于代码复用、功能增强。
它的本质是一个高阶函数(即接受一个函数作为参数并返回一个新函数)。
常见用途:
装饰器的本质是一个返回函数的函数,一般使用 @decorator_name
语法。
def my_decorator(func):
def wrapper():
print("开始执行函数")
func()
print("函数执行结束")
return wrapper
@my_decorator # 等价于 hello = my_decorator(hello)
def hello():
print("Hello, World!")
hello()
开始执行函数
Hello, World!
函数执行结束
说明:
my_decorator
是装饰器,接受 func
作为参数。wrapper
是内部函数,先执行装饰逻辑(print("开始执行函数")
),再执行 func()
。@my_decorator
作用于 hello()
,相当于 hello = my_decorator(hello)
。如果被装饰的函数有参数,装饰器内部的 wrapper
也必须接受参数:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("开始执行函数")
result = func(*args, **kwargs)
print("函数执行结束")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
print(add(3, 5))
开始执行函数
函数执行结束
8
说明:
*args, **kwargs
确保装饰器适用于任意参数的函数。如果想让装饰器本身也接收参数,需要再封装一层:
def repeat(n):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(3) # 等价于 hello = repeat(3)(hello)
def hello():
print("Hello!")
hello()
Hello!
Hello!
Hello!
说明:
repeat(n)
先接收参数 n
,返回 decorator
。decorator(func)
处理被装饰的函数,返回 wrapper
。@repeat(3)
使 hello()
执行 3 次。functools.wraps
保持原函数信息被装饰后,原函数的 __name__
、__doc__
会丢失:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("执行装饰器")
return func(*args, **kwargs)
return wrapper
@my_decorator
def hello():
"""这是 hello 函数"""
print("Hello!")
print(hello.__name__) # wrapper
print(hello.__doc__) # None
functools.wraps
import functools
def my_decorator(func):
@functools.wraps(func) # 保持原函数信息
def wrapper(*args, **kwargs):
print("执行装饰器")
return func(*args, **kwargs)
return wrapper
@my_decorator
def hello():
"""这是 hello 函数"""
print("Hello!")
print(hello.__name__) # hello
print(hello.__doc__) # 这是 hello 函数
结论:
@functools.wraps(func)
确保 hello()
仍保留自己的 __name__
和 __doc__
。装饰器不仅可以作用于函数,也可以作用于类。
def class_decorator(cls):
for attr, value in cls.__dict__.items():
if callable(value): # 只装饰方法
setattr(cls, attr, my_decorator(value))
return cls
@class_decorator
class MyClass:
def hello(self):
print("Hello, World!")
obj = MyClass()
obj.hello()
开始执行函数
Hello, World!
函数执行结束
__call__
作为装饰器class Timer:
def __call__(self, func):
def wrapper(*args, **kwargs):
import time
start = time.time()
result = func(*args, **kwargs)
end = time.time()
print(f"{func.__name__} 执行时间: {end - start:.4f} 秒")
return result
return wrapper
@Timer() # 这里实例化了 Timer
def slow_function():
import time
time.sleep(2)
print("函数执行完成")
slow_function()
函数执行完成
slow_function 执行时间: 2.0003 秒
说明:
__call__
使 Timer
类的实例可直接作为装饰器使用。Python 内置了一些常见装饰器,如:
@staticmethod
:定义静态方法,无需 self
。@classmethod
:定义类方法,cls
作为第一个参数。@property
:将方法转换为属性。class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name # 作为属性访问
@staticmethod
def greet():
print("Hello!")
@classmethod
def create(cls, name):
return cls(name)
p = Person("Alice")
print(p.name) # 访问属性,不是方法调用
p.greet() # 静态方法
new_p = Person.create("Bob") # 类方法
多个装饰器从内向外执行:
def deco1(func):
def wrapper():
print("执行 deco1")
func()
return wrapper
def deco2(func):
def wrapper():
print("执行 deco2")
func()
return wrapper
@deco1
@deco2
def hello():
print("Hello!")
hello()
执行 deco1
执行 deco2
Hello!
说明:
@deco2
先装饰 hello
,然后 @deco1
再装饰 deco2(hello)
。特性 | 说明 |
---|---|
基本装饰器 | @decorator 语法,包装函数 |
带参数装饰器 | 需要再封装一层 |
functools.wraps |
保持原函数信息 |
作用于类 | 可以装饰类或类方法 |
内置装饰器 | @staticmethod 、@classmethod 、@property |
多个装饰器 | 从内到外执行 |
装饰器是一种强大的工具,在 Web 开发(如 Flask)、日志、权限控制等方面非常有用!