装饰器是接收函数为参数并返回新函数的高阶函数,用于不修改原函数代码而增强其行为;支持@语法糖、带参配置及functools.wraps保留元信息。

装饰器本质是“函数的函数”
装饰器就是一个接收函数作为参数、返回新函数的可调用对象。它不修改原函数代码,却能增强其行为——比如加日志、计时、权限校验。写法上最常见的是用 @ 语法糖,但底层逻辑始终是:把目标函数传给装饰器,得到一个包装后的新函数。
最简装饰器长这样
先看一个无参装饰器的标准结构:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("调用前执行")
result = func(*args, **kwargs)
print("调用后执行")
return result
return wrapper
@my_decorator
def say_hello():
print("Hello!")
运行 say_hello() 会输出:
调用前执行
Hello!
调用后执行
立即学习“Python免费学习笔记(深入)”;
@语法糖背后发生了什么
这行 @my_decorator 等价于:
say_hello = my_decorator(say_hello)
也就是说:
• Python 在定义 say_hello 后,立刻用它作为参数调用 my_decorator
• my_decorator 返回 wrapper 函数
• 原来的 say_hello 名字被重新绑定到 wrapper 上
• 后续每次调用 say_hello(),实际执行的是 wrapper()
带参数的装饰器要多套一层
如果想让装饰器接收配置(比如日志级别、重试次数),就得再包一层:
- 最外层函数接收装饰器参数(如 level="INFO")
- 中间层才是真正的装饰器,接收被装饰函数
- 最内层 wrapper 执行逻辑并调用原函数
def log(level="INFO"):
def decorator(func):
def wrapper(*args, **kwargs):
print(f"[{level}] 开始执行 {func.__name__}")
result = func(*args, **kwargs)
print(f"[{level}] 执行完成")
return result
return wrapper
return decorator
@log("DEBUG")
def add(a, b):
return a + b
此时 @log("DEBUG") 先调用 log("DEBUG") 得到 decorator,再用它去装饰 add。
别忘了保留原函数的元信息
直接写装饰器会导致 say_hello.__name__ 变成 "wrapper",影响调试和文档生成。解决方法是用 functools.wraps:
from functools import wraps
def my_decorator(func):
@wraps(func) # 这一行关键
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
加上 @wraps(func) 后,wrapper 就会自动复制 func 的 __name__、__doc__、__module__ 等属性。










