1. 装饰器的基本语法
def decorator_function(original_function): def wrapper(*args, **kwargs): # 在调用原函数前添加额外功能 result = original_function(*args, **kwargs) # 在调用原函数后添加额外功能 return result return wrapper@decorator_functiondef target_function(): pass
💡语法要点:
2. 简单的装饰器:在函数执行前后各打印一句话
🌅示例:一个简单的日志装饰器
def my_decorator(func): """这是一个最简单的装饰器""" print("1. 装饰器 my_decorator 被调用了,它接收到的函数是:", func.__name__) def wrapper(): print("3. 正在执行 wrapper 函数,这是在调用原函数之前") func() # 调用原函数 print("5. 这是调用原函数之后,wrapper 函数执行完毕") print("2. 装饰器准备返回 wrapper 函数") return wrapper# 使用 @ 语法应用装饰器@my_decoratordef say_hi(): print("4. 原函数 say_hi 正在执行")# 调用被装饰后的函数print("--- 开始调用 say_hi() ---")say_hi()print("--- 调用结束 ---")
🏁输出结果:
1. 装饰器 my_decorator 被调用了,它接收到的函数是: say_hi2. 装饰器准备返回 wrapper 函数--- 开始调用 say_hi() ---3. 正在执行 wrapper 函数,这是在调用原函数之前4. 原函数 say_hi 正在执行5. 这是调用原函数之后,wrapper 函数执行完毕--- 调用结束 ---
2. 装饰器执行过程
上面的输出揭示了装饰器的完整执行过程,以下是流程图:
🎯关键点总结:
装饰器本身在函数定义时立即执行,不是在调用时执行。@my_decorator 背后的 say_hi = my_decorator(say_hi) 在定义阶段就完成了。
被装饰后的函数名指向了新的 wrapper 函数。之后每次调用 say_hi(),实际执行的都是 wrapper 内部的代码。
wrapper 内部可以在调用原函数前后添加任意代码,实现了“增强”效果。
3. 如果原函数需要参数怎么办?
上面的例子中 say_hi 没有参数,但实际函数往往需要参数。为了让装饰器能处理任意函数,需要在 wrapper 中使用 *args 和 **kwargs 来接收所有参数,并传递给原函数。
🧭示例:装饰带参数的函数
def my_decorator(func): def wrapper(*args, **kwargs): # wrapper 接收任意参数 print("调用前:做一些准备工作") result = func(*args, **kwargs) # 将参数原样传递给原函数 print("调用后:做一些清理工作") return result # 返回原函数的返回值 return wrapper@my_decoratordef greet(name, greeting="Hello"): print(f"{greeting}, {name}!") return "返回值:" + greeting# 调用output = greet("小明", greeting="你好")print("函数的返回值是:", output)
📌输出结果:
调用前:做一些准备工作你好, 小明!调用后:做一些清理工作函数的返回值是: 返回值:你好
这里 *args 和 **kwargs 收集了所有位置参数和关键字参数,使得装饰器可以应用于任何函数,无论它有多少参数。
4. 常见疑问
问:为什么装饰器里的 wrapper 要叫这个名字? 答:只是一个习惯名称,你可以叫任何名字,但通常用 wrapper 表示它是包装函数。
问:多个装饰器一起用会怎样? 答:它们会像剥洋葱一样一层层包装,从下往上应用。例如 @A 在上,@B 在下,相当于 func = A(B(func))。调用时先执行 A 的“前”代码,再执行 B 的“前”代码,然后原函数,然后 B 的“后”代码,最后 A 的“后”代码。对于新手,建议先掌握单个装饰器。
5. 一个完整的、可自己运行的简单示例
# 定义装饰器def simple_logger(func): print(f"【装饰器】正在装饰函数:{func.__name__}") def inner(): print(" [inner] 进入 inner 函数") func() print(" [inner] 退出 inner 函数") print("这是第2步就是马上执行下面的return inner(也就是马上执行inner装饰器函数)") return inner# 使用装饰器@simple_loggerdef test(): print(" [test] 原函数执行中")# 调用print("=" * 30)test()print("=" * 30)
运行这个代码,你会看到清晰的执行顺序。建议你把这段代码复制到自己的环境中运行,观察输出,这样理解会更深刻。